Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > c0394d3068b44395994f031447c8052d > files > 55

net-snmp-5.3.2.2-7.el5_4.2.src.rpm

477092:  [TAHI] Internet Address Translation Table on RFC4293

Author: Jan Safranek <jsafrane@redhat.com>
Upstream as SVN rev. 17431

Implement ipNetToPhysicalLastUpdated OID.

The value is estimated with every cache reload, which is once in 60 seconds by default.
That means the value reported by snmpd may differ from reality by one minute.
If anybody needs better precision, the cache timeout can be configured by setting
NET-SNMP-AGENT-MIB::nsCacheTimeout.1.3.6.1.2.1.4.35 to appropriate value by snmpset.

diff --git a/net-snmp/agent/mibgroup/ip-mib/data_access/arp_common.c b/net-snmp/agent/mibgroup/ip-mib/data_access/arp_common.c
index 6fca111..c4fdaa2 100644
--- a/net-snmp/agent/mibgroup/ip-mib/data_access/arp_common.c
+++ b/net-snmp/agent/mibgroup/ip-mib/data_access/arp_common.c
@@ -140,3 +140,41 @@ _access_arp_entry_release(netsnmp_arp_entry * entry, void *context)
 {
     netsnmp_access_arp_entry_free(entry);
 }
+
+/**
+ * Update given entry with new data. Calculate new arp_last_updated, if any
+ * field is changed.
+ */
+void netsnmp_access_arp_entry_update(netsnmp_arp_entry *entry,
+        netsnmp_arp_entry *new_data)
+{
+    int modified = 0;
+
+    if (entry->arp_ipaddress_len != new_data->arp_ipaddress_len
+            || memcmp(entry->arp_ipaddress, new_data->arp_ipaddress, entry->arp_ipaddress_len) != 0 ) {
+        modified = 1;
+        entry->arp_ipaddress_len = new_data->arp_ipaddress_len;
+        memcpy(entry->arp_ipaddress, new_data->arp_ipaddress, sizeof(entry->arp_ipaddress));
+    }
+    if (entry->arp_physaddress_len != new_data->arp_physaddress_len ||
+            memcmp(entry->arp_physaddress, new_data->arp_physaddress, entry->arp_physaddress_len) != 0) {
+         modified = 1;
+         entry->arp_physaddress_len = new_data->arp_physaddress_len;
+         memcpy(entry->arp_physaddress, new_data->arp_physaddress, sizeof(entry->arp_physaddress_len));
+     }
+    if (entry->arp_state != new_data->arp_state) {
+         modified = 1;
+         entry->arp_state = new_data->arp_state;
+     }
+    if (entry->arp_type != new_data->arp_type) {
+         modified = 1;
+         entry->arp_type = new_data->arp_type;
+     }
+    if (entry->flags != new_data->flags) {
+         modified = 1;
+         entry->flags = new_data->flags;
+     }
+
+    if (modified)
+        entry->arp_last_updated = netsnmp_get_agent_uptime();
+}
diff --git a/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable.c b/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable.c
index 689e127..f83226a 100644
--- a/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable.c
+++ b/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable.c
@@ -533,11 +533,7 @@ inetNetToMediaLastUpdated_get(inetNetToMediaTable_rowreq_ctx * rowreq_ctx,
      * TODO:231:o: |-> Extract the current value of the inetNetToMediaLastUpdated data.
      * copy (* inetNetToMediaLastUpdated_val_ptr ) from rowreq_ctx->data
      */
-    /*
-     * xxx-rks: get this value?
-     */
-    return MFD_SKIP;
-
+    *inetNetToMediaLastUpdated_val_ptr = rowreq_ctx->data->arp_last_updated;
     return MFD_SUCCESS;
 }                               /* inetNetToMediaLastUpdated_get */
 
diff --git a/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable.h b/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable.h
index 7f3fce2..3729c1a 100644
--- a/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable.h
+++ b/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable.h
@@ -155,6 +155,9 @@ config_require(ip-mib/inetNetToMediaTable/inetNetToMediaTable_data_access)
         int             inetNetToMediaRowStatus,
             inetNetToMediaRowStatus_undo;
 
+        /* flag, if the row was present in last read from operating system */
+        int valid;
+
         /*
          * storage for future expansion
          */
diff --git a/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable_data_access.c b/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable_data_access.c
index 019797f..00f3529 100644
--- a/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable_data_access.c
+++ b/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable_data_access.c
@@ -129,17 +129,34 @@ inetNetToMediaTable_container_init(netsnmp_container **container_ptr_ptr,
      * cache->enabled to 0.
      */
     cache->timeout = INETNETTOMEDIATABLE_CACHE_TIMEOUT; /* seconds */
+
+    /* We want to manually delete entries in the cache to keep LastUpdated
+     * timestamp. */
+    cache->flags |= NETSNMP_CACHE_DONT_FREE_BEFORE_LOAD
+                    | NETSNMP_CACHE_AUTO_RELOAD;
 }                               /* inetNetToMediaTable_container_init */
 
 /**
+ * Put all entries with valid !=1 to the list to delete.
+ */
+static void
+_collect_invalid_arp_ctx(inetNetToMediaTable_rowreq_ctx *ctx,
+        netsnmp_container *to_delete)
+{
+    if (ctx->valid)
+            ctx->valid = 0;
+    else
+        CONTAINER_INSERT(to_delete, ctx);
+}
+
+/**
  * check entry for update
- *
  */
 static void
-_snarf_arp_entry(netsnmp_arp_entry *arp_entry,
+_add_or_update_arp_entry(netsnmp_arp_entry *arp_entry,
                  netsnmp_container *container)
 {
-    inetNetToMediaTable_rowreq_ctx *rowreq_ctx;
+    inetNetToMediaTable_rowreq_ctx *rowreq_ctx, *old;
     int             inetAddressType;
 
     DEBUGTRACE;
@@ -166,8 +183,8 @@ _snarf_arp_entry(netsnmp_arp_entry *arp_entry,
     }
 
     /*
-     * allocate an row context and set the index(es), then add it to
-     * the container
+     * allocate an row context and set the index(es), then try to find it in
+     * the cache.
      */
     rowreq_ctx = inetNetToMediaTable_allocate_rowreq_ctx(arp_entry, NULL);
     if ((NULL != rowreq_ctx) &&
@@ -175,8 +192,23 @@ _snarf_arp_entry(netsnmp_arp_entry *arp_entry,
          (rowreq_ctx, rowreq_ctx->data->if_index, inetAddressType,
           rowreq_ctx->data->arp_ipaddress,
           rowreq_ctx->data->arp_ipaddress_len))) {
-        rowreq_ctx->inetNetToMediaRowStatus = ROWSTATUS_ACTIVE;
-        CONTAINER_INSERT(container, rowreq_ctx);
+
+        /* try to find old entry */
+        old = CONTAINER_FIND(container, rowreq_ctx);
+        if (old != NULL) {
+            /* the entry is already there, update it */
+            netsnmp_access_arp_entry_update(old->data, arp_entry);
+            old->valid = 1; /* do not delete it in following sweep */
+            /* delete the auxiliary context we used to find the entry
+             * (this deletes also arp_entry) */
+            inetNetToMediaTable_release_rowreq_ctx(rowreq_ctx);
+        } else {
+            /* create new entry and add it to the cache*/
+            rowreq_ctx->inetNetToMediaRowStatus = ROWSTATUS_ACTIVE;
+            rowreq_ctx->data->arp_last_updated = netsnmp_get_agent_uptime();
+            rowreq_ctx->valid = 1; /* do not delete it in following sweep */
+            CONTAINER_INSERT(container, rowreq_ctx);
+        }
     } else {
         if (rowreq_ctx) {
             snmp_log(LOG_ERR, "error setting index while loading "
@@ -253,6 +285,7 @@ int
 inetNetToMediaTable_container_load(netsnmp_container *container)
 {
     netsnmp_container *arp_container;
+    netsnmp_container *to_delete = netsnmp_container_find("lifo");
 
     DEBUGMSGTL(("verbose:inetNetToMediaTable:inetNetToMediaTable_cache_load", "called\n"));
 
@@ -272,10 +305,24 @@ inetNetToMediaTable_container_load(netsnmp_container *container)
      * we just got a fresh copy of data. snarf data
      */
     CONTAINER_FOR_EACH(arp_container,
-                       (netsnmp_container_obj_func *) _snarf_arp_entry,
+                       (netsnmp_container_obj_func *) _add_or_update_arp_entry,
                        container);
 
     /*
+     * Delete all cached entries, which were not provided by
+     * netsnmp_access_arp_container_load
+     */
+    CONTAINER_FOR_EACH(container,
+                       (netsnmp_container_obj_func *) _collect_invalid_arp_ctx,
+                       to_delete);
+    while (CONTAINER_SIZE(to_delete)) {
+        inetNetToMediaTable_rowreq_ctx *ctx = CONTAINER_FIRST(to_delete);
+        CONTAINER_REMOVE(container, ctx);
+        inetNetToMediaTable_release_rowreq_ctx(ctx);
+        CONTAINER_REMOVE(to_delete, NULL);
+        }
+
+    /*
      * free the container. we've either claimed each entry, or released it,
      * so the access function doesn't need to clear the container.
      */
diff --git a/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable_data_access.h b/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable_data_access.h
index cc0434b..3e655b9 100644
--- a/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable_data_access.h
+++ b/net-snmp/agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable_data_access.h
@@ -44,7 +44,7 @@ extern          "C" {
      * TODO:180:o: Review inetNetToMediaTable cache timeout.
      * The number of seconds before the cache times out
      */
-#define INETNETTOMEDIATABLE_CACHE_TIMEOUT   60
+#define INETNETTOMEDIATABLE_CACHE_TIMEOUT   15
 
     void            inetNetToMediaTable_container_init(netsnmp_container
                                                        **container_ptr_ptr,
diff --git a/net-snmp/include/net-snmp/data_access/arp.h b/net-snmp/include/net-snmp/data_access/arp.h
index ee775b7..93c193c 100644
--- a/net-snmp/include/net-snmp/data_access/arp.h
+++ b/net-snmp/include/net-snmp/data_access/arp.h
@@ -83,6 +83,7 @@ typedef struct netsnmp_arp_s {
    u_char    arp_type;           /* inetNetToMediaType 1-5 */
    u_char    arp_state;          /* inetNetToMediaState 1-7 */
 
+   u_long    arp_last_updated;   /* timeticks of last update */
 } netsnmp_arp_entry;
 
 
@@ -119,6 +120,9 @@ netsnmp_access_arp_entry_create(void);
 
 void netsnmp_access_arp_entry_free(netsnmp_arp_entry * entry);
 
+void netsnmp_access_arp_entry_update(netsnmp_arp_entry *entry,
+        netsnmp_arp_entry *new_data);
+
 /*
  * find entry in container
  */