On 11/24/2010 04:43 PM, Timo Teräs wrote:
> Anyway, I attached where I am currently at. It kills the old proc based
> thing, and adds the new netlink based ARP container stuff. I need to
> still: rewrite the procfs stuff so we don't depend on netlink (or do I
> have to do this? every sane linux should have netlink there), and to add
> the flag to generic caching code, so timers are treated differently.
>
> I'm mainly interested if anyone has a say on the modifications to
> include/net-snmp/data_access/arp.h -- I'm basically rewriting that API
> now. Also, is it ok to use the existing netsnmp_arp_entry.flags for my
> NETSNMP_ACCESS_ARP_ENTRY_FLAG_DELETE ?
>
> Oh, it also looks like the kernel does not send RTM_DELNEIGH messages
> when the entry is purged. Instead we need to treat RTM_NEWNEIGH with
> NUD_FAILED as indication of the entry being deleted.
>
> But as such, this code seems to be already able to keep up the cached
> neigh table in sync with the kernel's table. Did basic testing on this.
>
> Feedback appreciated.
Find attached version 2 of the patch. I've fixed it to again fallback to
procfs method if netlink is not available. Also recovery from netlink
synchronization lost should work (netlink socket going full).
The only thing missing is proper default values for the timeouts, and
making them configurable. Possibly turning off the netlink monitoring is
not there either, but I'm not sure we want it: listening for the events
is very lightweight and only enabled if there's been recently related
queries.
Please review for inclusion.
Thanks,
Timo
Index: include/net-snmp/data_access/arp.h
===================================================================
--- include/net-snmp/data_access/arp.h (revision 19662)
+++ include/net-snmp/data_access/arp.h (working copy)
@@ -73,6 +73,7 @@
int flags; /* for net-snmp use */
+ unsigned generation;
oid if_index;
u_char arp_physaddress[NETSNMP_ACCESS_ARP_PHYSADDR_BUF_SIZE];
@@ -86,11 +87,13 @@
u_long arp_last_updated; /* timeticks of last update */
} netsnmp_arp_entry;
+#define NETSNMP_ACCESS_ARP_ENTRY_FLAG_DELETE 0x00000001
/**---------------------------------------------------------------------*/
/*
* ACCESS function prototypes
*/
+#if 0
/*
* ifcontainer init
*/
@@ -110,8 +113,35 @@
#define NETSNMP_ACCESS_ARP_FREE_NOFLAGS 0x0000
#define NETSNMP_ACCESS_ARP_FREE_DONT_CLEAR 0x0001
#define NETSNMP_ACCESS_ARP_FREE_KEEP_CONTAINER 0x0002
+#endif
+struct netsnmp_arp_access_s;
+typedef struct netsnmp_arp_access_s netsnmp_arp_access;
+typedef void (NetsnmpAccessArpUpdate)(netsnmp_arp_access *, netsnmp_arp_entry*);
+typedef void (NetsnmpAccessArpGC) (netsnmp_arp_access *);
+
+struct netsnmp_arp_access_s {
+ void *magic;
+ void *arch_magic;
+ int synchronized;
+ unsigned generation;
+ NetsnmpAccessArpUpdate *update_hook;
+ NetsnmpAccessArpGC *gc_hook;
+};
+
+
+netsnmp_arp_access *
+netsnmp_access_arp_create(u_int init_flags,
+ NetsnmpAccessArpUpdate *update_hook,
+ NetsnmpAccessArpGC *gc_hook,
+ int *cache_timeout, int *cache_flags);
+#define NETSNMP_ACCESS_ARP_CREATE_NOFLAGS 0x0000
+
+int netsnmp_access_arp_delete(netsnmp_arp_access *access);
+int netsnmp_access_arp_load(netsnmp_arp_access *access);
+int netsnmp_access_arp_unload(netsnmp_arp_access *access);
+
/*
* create/free a arp+entry
*/
Index: include/net-snmp/agent/cache_handler.h
===================================================================
--- include/net-snmp/agent/cache_handler.h (revision 19662)
+++ include/net-snmp/agent/cache_handler.h (working copy)
@@ -119,6 +119,7 @@
#define NETSNMP_CACHE_DONT_AUTO_RELEASE 0x0008
#define NETSNMP_CACHE_PRELOAD 0x0010
#define NETSNMP_CACHE_AUTO_RELOAD 0x0020
+#define NETSNMP_CACHE_DYNAMIC_TIMEOUT 0x0040
#define NETSNMP_CACHE_HINT_HANDLER_ARGS 0x1000
Index: agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable.h
===================================================================
--- agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable.h (revision 19662)
+++ agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable.h (working copy)
@@ -155,9 +155,6 @@
int inetNetToMediaRowStatus,
inetNetToMediaRowStatus_undo;
- /* flag, if the row was present in last read from operating system */
- int valid;
-
/*
* storage for future expansion
*/
Index: agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable_data_access.c
===================================================================
--- agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable_data_access.c (revision 19662)
+++ agent/mibgroup/ip-mib/inetNetToMediaTable/inetNetToMediaTable_data_access.c (working copy)
@@ -15,9 +15,10 @@
* include our parent header
*/
#include "inetNetToMediaTable.h"
+#include "inetNetToMediaTable_data_access.h"
+static netsnmp_arp_access * arp_access = NULL;
-#include "inetNetToMediaTable_data_access.h"
/** @ingroup interface
* @addtogroup data_access data_access: Routines to access data
@@ -71,85 +72,6 @@
*/
/**
- * container initialization
- *
- * @param container_ptr_ptr A pointer to a container pointer. If you
- * create a custom container, use this parameter to return it
- * to the MFD helper. If set to NULL, the MFD helper will
- * allocate a container for you.
- * @param cache A pointer to a cache structure. You can set the timeout
- * and other cache flags using this pointer.
- *
- * This function is called at startup to allow you to customize certain
- * aspects of the access method. For the most part, it is for advanced
- * users. The default code should suffice for most cases. If no custom
- * container is allocated, the MFD code will create one for your.
- *
- * This is also the place to set up cache behavior. The default, to
- * simply set the cache timeout, will work well with the default
- * container. If you are using a custom container, you may want to
- * look at the cache helper documentation to see if there are any
- * flags you want to set.
- *
- * @remark
- * This would also be a good place to do any initialization needed
- * for you data source. For example, opening a connection to another
- * process that will supply the data, opening a database, etc.
- */
-void
-inetNetToMediaTable_container_init(netsnmp_container **container_ptr_ptr,
- netsnmp_cache * cache)
-{
- DEBUGMSGTL(("verbose:inetNetToMediaTable:inetNetToMediaTable_container_init", "called\n"));
-
- if (NULL == container_ptr_ptr) {
- snmp_log(LOG_ERR,
- "bad container param to inetNetToMediaTable_container_init\n");
- return;
- }
-
- /*
- * For advanced users, you can use a custom container. If you
- * do not create one, one will be created for you.
- */
- *container_ptr_ptr = NULL;
-
- if (NULL == cache) {
- snmp_log(LOG_ERR,
- "bad cache param to inetNetToMediaTable_container_init\n");
- return;
- }
-
- /*
- * TODO:345:A: Set up inetNetToMediaTable cache properties.
- *
- * Also for advanced users, you can set parameters for the
- * cache. Do not change the magic pointer, as it is used
- * by the MFD helper. To completely disable caching, set
- * 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
@@ -195,10 +117,16 @@
/* try to find old entry */
old = (inetNetToMediaTable_rowreq_ctx*)CONTAINER_FIND(container, rowreq_ctx);
- if (old != NULL) {
+ if (arp_entry->flags & NETSNMP_ACCESS_ARP_ENTRY_FLAG_DELETE) {
+ /* delete existing entry */
+ if (old != NULL) {
+ CONTAINER_REMOVE(container, old);
+ inetNetToMediaTable_release_rowreq_ctx(old);
+ }
+ inetNetToMediaTable_release_rowreq_ctx(rowreq_ctx);
+ } else 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);
@@ -206,7 +134,6 @@
/* 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 {
@@ -219,7 +146,112 @@
}
}
+static void _arp_hook_update(netsnmp_arp_access *access, netsnmp_arp_entry *entry)
+{
+ _add_or_update_arp_entry(entry, access->magic);
+}
+
+typedef struct {
+ unsigned generation;
+ netsnmp_container *to_delete;
+} _collect_ctx;
+
/**
+ * Put all entries with outdated generation to deletion list.
+ */
+static void
+_collect_invalid_arp_ctx(inetNetToMediaTable_rowreq_ctx *ctx,
+ _collect_ctx *cctx)
+{
+ if (ctx->data->generation != cctx->generation)
+ CONTAINER_INSERT(cctx->to_delete, ctx);
+}
+
+static void _arp_hook_gc(netsnmp_arp_access *access)
+{
+ netsnmp_container *container = access->magic;
+ _collect_ctx cctx;
+
+ cctx.to_delete = netsnmp_container_find("lifo");
+ cctx.generation = access->generation;
+
+ CONTAINER_FOR_EACH(container,
+ (netsnmp_container_obj_func *) _collect_invalid_arp_ctx,
+ &cctx);
+
+ while (CONTAINER_SIZE(cctx.to_delete)) {
+ inetNetToMediaTable_rowreq_ctx *ctx = (inetNetToMediaTable_rowreq_ctx*)CONTAINER_FIRST(cctx.to_delete);
+ CONTAINER_REMOVE(container, ctx);
+ inetNetToMediaTable_release_rowreq_ctx(ctx);
+ CONTAINER_REMOVE(cctx.to_delete, NULL);
+ }
+ CONTAINER_FREE(cctx.to_delete);
+}
+
+/**
+ * container initialization
+ *
+ * @param container_ptr_ptr A pointer to a container pointer. If you
+ * create a custom container, use this parameter to return it
+ * to the MFD helper. If set to NULL, the MFD helper will
+ * allocate a container for you.
+ * @param cache A pointer to a cache structure. You can set the timeout
+ * and other cache flags using this pointer.
+ *
+ * This function is called at startup to allow you to customize certain
+ * aspects of the access method. For the most part, it is for advanced
+ * users. The default code should suffice for most cases. If no custom
+ * container is allocated, the MFD code will create one for your.
+ *
+ * This is also the place to set up cache behavior. The default, to
+ * simply set the cache timeout, will work well with the default
+ * container. If you are using a custom container, you may want to
+ * look at the cache helper documentation to see if there are any
+ * flags you want to set.
+ *
+ * @remark
+ * This would also be a good place to do any initialization needed
+ * for you data source. For example, opening a connection to another
+ * process that will supply the data, opening a database, etc.
+ */
+void
+inetNetToMediaTable_container_init(netsnmp_container **container_ptr_ptr,
+ netsnmp_cache * cache)
+{
+ DEBUGMSGTL(("verbose:inetNetToMediaTable:inetNetToMediaTable_container_init", "called\n"));
+
+ if (NULL == container_ptr_ptr) {
+ snmp_log(LOG_ERR,
+ "bad container param to inetNetToMediaTable_container_init\n");
+ return;
+ }
+
+ /*
+ * For advanced users, you can use a custom container. If you
+ * do not create one, one will be created for you.
+ */
+ *container_ptr_ptr = NULL;
+
+ if (NULL == cache) {
+ snmp_log(LOG_ERR,
+ "bad cache param to inetNetToMediaTable_container_init\n");
+ return;
+ }
+
+ arp_access = netsnmp_access_arp_create(
+ NETSNMP_ACCESS_ARP_CREATE_NOFLAGS,
+ _arp_hook_update,
+ _arp_hook_gc,
+ &cache->timeout,
+ &cache->flags);
+ if (arp_access == NULL) {
+ snmp_log(LOG_ERR,
+ "unable to create arp access in inetNetToMediaTable_container_init\n");
+ return;
+ }
+} /* inetNetToMediaTable_container_init */
+
+/**
* container shutdown
*
* @param container_ptr A pointer to the container.
@@ -240,12 +272,16 @@
{
DEBUGMSGTL(("verbose:inetNetToMediaTable:inetNetToMediaTable_container_shutdown", "called\n"));
+ if (NULL != arp_access) {
+ netsnmp_access_arp_delete(arp_access);
+ arp_access = NULL;
+ }
+
if (NULL == container_ptr) {
snmp_log(LOG_ERR,
"bad params to inetNetToMediaTable_container_shutdown\n");
return;
}
-
} /* inetNetToMediaTable_container_shutdown */
/**
@@ -284,54 +320,12 @@
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"));
- /*
- * TODO:351:M: |-> Load/update data in the inetNetToMediaTable container.
- * loop over your inetNetToMediaTable data, allocate a rowreq context,
- * set the index(es) [and data, optionally] and insert into
- * the container.
- */
- arp_container =
- netsnmp_access_arp_container_load(NULL,
- NETSNMP_ACCESS_ARP_LOAD_NOFLAGS);
- if (NULL == arp_container)
- return MFD_RESOURCE_UNAVAILABLE; /* msg already logged */
+ arp_access->magic = container;
+ if (netsnmp_access_arp_load(arp_access) < 0)
+ return MFD_ERROR;
- /*
- * we just got a fresh copy of data. snarf data
- */
- CONTAINER_FOR_EACH(arp_container,
- (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 = (inetNetToMediaTable_rowreq_ctx*)CONTAINER_FIRST(to_delete);
- CONTAINER_REMOVE(container, ctx);
- inetNetToMediaTable_release_rowreq_ctx(ctx);
- CONTAINER_REMOVE(to_delete, NULL);
- }
- CONTAINER_FREE(to_delete);
-
- /*
- * free the container. we've either claimed each entry, or released it,
- * so the access function doesn't need to clear the container.
- */
- netsnmp_access_arp_container_free(arp_container,
- NETSNMP_ACCESS_ARP_FREE_DONT_CLEAR);
-
- DEBUGMSGT(("verbose:inetNetToMediaTable:inetNetToMediaTable_cache_load", "%" NETSNMP_PRIz "u records\n", CONTAINER_SIZE(container)));
-
return MFD_SUCCESS;
} /* inetNetToMediaTable_container_load */
@@ -353,6 +347,11 @@
{
DEBUGMSGTL(("verbose:inetNetToMediaTable:inetNetToMediaTable_container_free", "called\n"));
+ if (NULL != arp_access) {
+ netsnmp_access_arp_unload(arp_access);
+ arp_access->magic = NULL;
+ }
+
/*
* TODO:380:M: Free inetNetToMediaTable container data.
*/
Index: agent/mibgroup/ip-mib/data_access/arp_linux.c
===================================================================
--- agent/mibgroup/ip-mib/data_access/arp_linux.c (revision 19662)
+++ agent/mibgroup/ip-mib/data_access/arp_linux.c (working copy)
@@ -1,441 +0,0 @@
-/*
- * Interface MIB architecture support
- */
-#include <net-snmp/net-snmp-config.h>
-#include <net-snmp/net-snmp-includes.h>
-
-#include <net-snmp/agent/net-snmp-agent-includes.h>
-#include <net-snmp/data_access/arp.h>
-#include <net-snmp/data_access/interface.h>
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <net/if_arp.h>
-#include <arpa/inet.h>
-#include <linux/types.h>
-#include <asm/types.h>
-#ifdef HAVE_LINUX_RTNETLINK_H
-#include <linux/rtnetlink.h>
-#endif
-#ifdef NETSNMP_ENABLE_IPV6
-#define NIP6(addr) \
- ntohs((addr).s6_addr16[0]), \
- ntohs((addr).s6_addr16[1]), \
- ntohs((addr).s6_addr16[2]), \
- ntohs((addr).s6_addr16[3]), \
- ntohs((addr).s6_addr16[4]), \
- ntohs((addr).s6_addr16[5]), \
- ntohs((addr).s6_addr16[6]), \
- ntohs((addr).s6_addr16[7])
-#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-#endif
-
-int _load_v4(netsnmp_container *container, int idx_offset);
-#ifdef NETSNMP_ENABLE_IPV6
-static int _load_v6(netsnmp_container *container, int idx_offset);
-#endif
-#ifdef HAVE_LINUX_RTNETLINK_H
-int get_translation_table_info (int sd, int *status,
- char *buff, size_t size);
-int fillup_entry_info(netsnmp_arp_entry *entry,
- struct nlmsghdr *nlmp);
-#endif
-/**
- */
-int
-netsnmp_access_arp_container_arch_load(netsnmp_container *container)
-{
- int rc = 0, idx_offset = 0;
-
- rc = _load_v4(container, idx_offset);
- if(rc < 0) {
- u_int flags = NETSNMP_ACCESS_ARP_FREE_KEEP_CONTAINER;
- netsnmp_access_arp_container_free(container, flags);
- }
-
-#if defined (NETSNMP_ENABLE_IPV6)
- idx_offset = (rc < 0) ? 0 : rc;
-
- rc = _load_v6(container, idx_offset);
- if(rc < 0) {
- u_int flags = NETSNMP_ACCESS_ARP_FREE_KEEP_CONTAINER;
- netsnmp_access_arp_container_free(container, flags);
- }
-#endif
-
- /*
- * return no errors (0) if we found any interfaces
- */
- if(rc > 0)
- rc = 0;
-
- return rc;
-}
-
-/**
- */
-int
-_load_v4(netsnmp_container *container, int idx_offset)
-{
- FILE *in;
- char line[128];
- int rc = 0;
- netsnmp_arp_entry *entry;
- char arp[3*NETSNMP_ACCESS_ARP_PHYSADDR_BUF_SIZE+1];
- char *arp_token;
- int i;
-
- netsnmp_assert(NULL != container);
-
-#define PROCFILE "/proc/net/arp"
- if (!(in = fopen(PROCFILE, "r"))) {
- snmp_log(LOG_DEBUG,"could not open " PROCFILE "\n");
- return -2;
- }
-
- /*
- * Get rid of the header line
- */
- fgets(line, sizeof(line), in);
-
- /*
- * IP address | HW | Flag | HW address | Mask | Device
- * 192.168.1.4 0x1 0x2 00:40:63:CC:1C:8C * eth0
- */
- while (fgets(line, sizeof(line), in)) {
-
- int za, zb, zc, zd;
- unsigned int tmp_flags;
- char ifname[21];
-
- rc = sscanf(line,
- "%d.%d.%d.%d 0x%*x 0x%x %96s %*[^ ] %20s\n",
- &za, &zb, &zc, &zd, &tmp_flags, arp, ifname);
- if (7 != rc) {
- snmp_log(LOG_ERR, PROCFILE " data format error (%d!=12)\n", rc);
- snmp_log(LOG_ERR, " line ==|%s|\n", line);
- continue;
- }
- DEBUGMSGTL(("access:arp:container",
- "ip addr %d.%d.%d.%d, flags 0x%X, hw addr "
- "%s, name %s\n",
- za,zb,zc,zd, tmp_flags, arp, ifname ));
-
- /*
- */
- entry = netsnmp_access_arp_entry_create();
- if(NULL == entry) {
- rc = -3;
- break;
- }
-
- /*
- * look up ifIndex
- */
- entry->if_index = netsnmp_access_interface_index_find(ifname);
- if(0 == entry->if_index) {
- snmp_log(LOG_ERR,"couldn't find ifIndex for '%s', skipping\n",
- ifname);
- netsnmp_access_arp_entry_free(entry);
- continue;
- }
-
- /*
- * now that we've passed all the possible 'continue', assign
- * index offset.
- */
- entry->ns_arp_index = ++idx_offset;
-
- /*
- * parse ip addr
- */
- entry->arp_ipaddress[0] = za;
- entry->arp_ipaddress[1] = zb;
- entry->arp_ipaddress[2] = zc;
- entry->arp_ipaddress[3] = zd;
- entry->arp_ipaddress_len = 4;
-
- /*
- * parse hw addr
- */
- for (arp_token = strtok(arp, ":"), i=0; arp_token != NULL; arp_token = strtok(NULL, ":"), i++) {
- entry->arp_physaddress[i] = strtol(arp_token, NULL, 16);
- }
- entry->arp_physaddress_len = i;
-
- /*
- * what can we do with hw? from arp manpage:
-
- default value of this parameter is ether (i.e. hardware code
- 0x01 for IEEE 802.3 10Mbps Ethernet). Other values might
- include network technologies such as ARCnet (arcnet) , PROnet
- (pronet) , AX.25 (ax25) and NET/ROM (netrom).
- */
-
- /*
- * parse mask
- */
- /* xxx-rks: what is mask? how to interpret '*'? */
-
-
- /*
- * process type
- */
- if(tmp_flags & ATF_PERM)
- entry->arp_type = INETNETTOMEDIATYPE_STATIC;
- else
- entry->arp_type = INETNETTOMEDIATYPE_DYNAMIC;
-
- /*
- * process status
- * if flags are 0, we can't tell the difference between
- * stale or incomplete.
- */
- if(tmp_flags & ATF_COM)
- entry->arp_state = INETNETTOMEDIASTATE_REACHABLE;
- else
- entry->arp_state = INETNETTOMEDIASTATE_UNKNOWN;
-
- /*
- * add entry to container
- */
- if (CONTAINER_INSERT(container, entry) < 0)
- {
- DEBUGMSGTL(("access:arp:container","error with arp_entry: insert into container failed.\n"));
- netsnmp_access_arp_entry_free(entry);
- continue;
- }
- }
-
- fclose(in);
- if( rc < 0 )
- return rc;
-
- return idx_offset;
-}
-
-#if defined (NETSNMP_ENABLE_IPV6)
-static int
-_load_v6(netsnmp_container *container, int idx_offset)
-{
- char buffer[16384];
-#if defined(HAVE_LINUX_RTNETLINK_H)
- struct nlmsghdr *nlmp;
-#endif
- int sd = 0;
- int status = 0;
- int rc = 0;
- int len, req_len;
- netsnmp_arp_entry *entry;
-
- netsnmp_assert(NULL != container);
-#if defined(HAVE_LINUX_RTNETLINK_H)
- if((sd = socket (PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) {
- snmp_log(LOG_ERR,"Unable to create netlink socket\n");
- return -2;
- }
-
- if(get_translation_table_info (sd, &status, buffer, sizeof(buffer)) < 0) {
- snmp_log(LOG_ERR,"Unable to fetch translation table info\n");
- close(sd);
- return -2;
- }
-
- for (nlmp = (struct nlmsghdr *)buffer; status > sizeof(*nlmp); ) {
- len = nlmp->nlmsg_len;
- req_len = len - sizeof(*nlmp);
- if (req_len < 0 || len > status) {
- snmp_log(LOG_ERR,"invalid length\n");
- return -2;
- }
- if (!NLMSG_OK (nlmp, status)) {
- snmp_log(LOG_ERR,"NLMSG not OK\n");
- return -2;
- }
- entry = netsnmp_access_arp_entry_create();
- if(NULL == entry) {
- rc = -3;
- break;
- }
- entry->ns_arp_index = ++idx_offset;
- if(fillup_entry_info (entry, nlmp) < 0) {
- NETSNMP_LOGONCE((LOG_ERR, "filling entry info failed\n"));
- DEBUGMSGTL(("access:arp:load_v6", "filling entry info failed\n"));
- netsnmp_access_arp_entry_free(entry);
- status -= NLMSG_ALIGN(len);
- nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len));
- continue;
- }
- CONTAINER_INSERT(container, entry);
- status -= NLMSG_ALIGN(len);
- nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len));
- }
-
- close(sd);
-#endif
- if(rc<0) {
- return rc;
- }
-
- return idx_offset;
-}
-#if defined(HAVE_LINUX_RTNETLINK_H)
-int
-get_translation_table_info (int sd, int *status, char *buff, size_t size)
-{
- struct {
- struct nlmsghdr n;
- struct ndmsg r;
- char buf[1024];
- } req;
- struct rtattr *rta;
-
- memset(&req, 0, sizeof(req));
- req.n.nlmsg_len = NLMSG_LENGTH (sizeof(struct ndmsg));
- req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
- req.n.nlmsg_type = RTM_GETNEIGH;
-
- req.r.ndm_family = AF_INET6;
- rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len));
- rta->rta_len = RTA_LENGTH(16);
-
- if(send(sd, &req, req.n.nlmsg_len, 0) < 0) {
- snmp_log(LOG_ERR,"Sending request failed\n");
- return -1;
- }
- if((*status = recv(sd, buff, size, 0)) < 0) {
- snmp_log(LOG_ERR,"Recieving request failed\n");
- return -1;
- }
- if(*status == 0) {
- snmp_log(LOG_ERR,"End of file\n");
- return -1;
- }
- return 0;
-}
-
-int
-fillup_entry_info(netsnmp_arp_entry *entry, struct nlmsghdr *nlmp)
-{
- struct ndmsg *rtmp;
- struct in6_addr *in6p;
- struct rtattr *tb[NDA_MAX + 1], *rta;
- size_t in_len, out_len;
- unsigned int i;
- int length;
- char addr[40];
- u_char *buf;
- u_char *hwaddr;
-
- rtmp = (struct ndmsg *) NLMSG_DATA(nlmp);
- if (nlmp->nlmsg_type != RTM_NEWNEIGH
- && nlmp->nlmsg_type != RTM_DELNEIGH) {
- DEBUGMSGTL(("access:arp:load_v6",
- "Wrong Netlink message type %d\n", nlmp->nlmsg_type));
- return -1;
- }
-
- if (rtmp->ndm_state != NUD_NOARP) {
- memset(tb, 0, sizeof(struct rtattr *) * (NDA_MAX + 1));
- length = nlmp->nlmsg_len - NLMSG_LENGTH(sizeof(*rtmp));
- /*
- * this is what the kernel-removed NDA_RTA define did
- */
- rta = ((struct rtattr *) (((char *) (rtmp)) +
- NLMSG_ALIGN(sizeof(struct ndmsg))));
- while (RTA_OK(rta, length)) {
- if (rta->rta_type <= NDA_MAX)
- tb[rta->rta_type] = rta;
- rta = RTA_NEXT(rta, length);
- }
- if (length) {
- DEBUGMSGTL(("access:arp:load_v6", "Received uneven number of"
- " messages - %d bytes remaining\n", length));
- return -1;
- }
- /*
- * Fill up the index
- */
- entry->if_index = rtmp->ndm_ifindex;
- /*
- * Fill up ip address
- */
- if (tb[NDA_DST]) {
- memset(&addr, '\0', sizeof(addr));
- in6p = (struct in6_addr *) RTA_DATA(tb[NDA_DST]);
- sprintf(addr, NIP6_FMT, NIP6(*in6p));
- in_len = entry->arp_ipaddress_len =
- sizeof(entry->arp_ipaddress);
- netsnmp_assert(16 == in_len);
- out_len = 0;
- buf = entry->arp_ipaddress;
- if (1 != netsnmp_hex_to_binary(&buf, &in_len,
- &out_len, 0, addr, ":")) {
- snmp_log(LOG_ERR, "error parsing '%s', skipping\n",
- entry->arp_ipaddress);
- return -1;
- }
- netsnmp_assert(16 == out_len);
- entry->arp_ipaddress_len = out_len;
- }
- if (tb[NDA_LLADDR]) {
- memset(&addr, '\0', sizeof(addr));
- hwaddr = RTA_DATA(tb[NDA_LLADDR]);
- entry->arp_physaddress_len = RTA_PAYLOAD(tb[NDA_LLADDR]);
- buf = entry->arp_physaddress;
- for (i = 0; i < entry->arp_physaddress_len; i++)
- entry->arp_physaddress[i] = hwaddr[i];
- }
-
- switch (rtmp->ndm_state) {
- case NUD_INCOMPLETE:
- entry->arp_state = INETNETTOMEDIASTATE_INCOMPLETE;
- break;
- case NUD_REACHABLE:
- case NUD_PERMANENT:
- entry->arp_state = INETNETTOMEDIASTATE_REACHABLE;
- break;
- case NUD_STALE:
- entry->arp_state = INETNETTOMEDIASTATE_STALE;
- break;
- case NUD_DELAY:
- entry->arp_state = INETNETTOMEDIASTATE_DELAY;
- break;
- case NUD_PROBE:
- entry->arp_state = INETNETTOMEDIASTATE_PROBE;
- break;
- case NUD_FAILED:
- entry->arp_state = INETNETTOMEDIASTATE_INVALID;
- break;
- case NUD_NONE:
- entry->arp_state = INETNETTOMEDIASTATE_UNKNOWN;
- break;
- }
-
- switch (rtmp->ndm_state) {
- case NUD_INCOMPLETE:
- case NUD_FAILED:
- case NUD_NONE:
- entry->arp_type = INETNETTOMEDIATYPE_INVALID;
- break;
- case NUD_REACHABLE:
- case NUD_STALE:
- case NUD_DELAY:
- case NUD_PROBE:
- entry->arp_type = INETNETTOMEDIATYPE_DYNAMIC;
- break;
- case NUD_PERMANENT:
- entry->arp_type = INETNETTOMEDIATYPE_STATIC;
- break;
- default:
- entry->arp_type = INETNETTOMEDIATYPE_LOCAL;
- break;
- }
- } else {
- return -1; /* could not create data for this interface */
- }
-
- return 0;
-}
-#endif
-#endif
Index: agent/mibgroup/ip-mib/data_access/arp_netlink.c
===================================================================
--- agent/mibgroup/ip-mib/data_access/arp_netlink.c (revision 0)
+++ agent/mibgroup/ip-mib/data_access/arp_netlink.c (revision 0)
@@ -0,0 +1,289 @@
+/*
+ * Interface MIB architecture support
+ */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include <net-snmp/data_access/arp.h>
+#include <net-snmp/data_access/interface.h>
+
+#include <errno.h>
+#include <linux/rtnetlink.h>
+
+
+static int fillup_entry_info(netsnmp_arp_entry *entry, struct nlmsghdr *h);
+static void netsnmp_access_arp_read_netlink(int fd, void *data);
+
+/**
+ */
+netsnmp_arp_access *
+netsnmp_access_arp_create(u_int init_flags,
+ NetsnmpAccessArpUpdate *update_hook,
+ NetsnmpAccessArpGC *gc_hook,
+ int *cache_timeout, int *cache_flags)
+{
+ netsnmp_arp_access *access;
+
+ access = SNMP_MALLOC_TYPEDEF(netsnmp_arp_access);
+ if (NULL == access) {
+ snmp_log(LOG_ERR,"malloc error in netsnmp_access_arp_create\n");
+ return NULL;
+ }
+
+ access->arch_magic = NULL;
+ access->magic = NULL;
+ access->update_hook = update_hook;
+ access->gc_hook = gc_hook;
+ access->synchronized = 0;
+
+ if (cache_timeout != NULL)
+ *cache_timeout = 5;
+ if (cache_flags != NULL)
+ *cache_flags |= NETSNMP_CACHE_DYNAMIC_TIMEOUT;
+
+ return access;
+}
+
+int netsnmp_access_arp_delete(netsnmp_arp_access *access)
+{
+ if (NULL == access)
+ return 0;
+
+ netsnmp_access_arp_unload(access);
+ free(access);
+
+ return 0;
+}
+
+int netsnmp_access_arp_load(netsnmp_arp_access *access)
+{
+ int r, fd = (int) access->arch_magic;
+ struct {
+ struct nlmsghdr n;
+ struct ndmsg r;
+ } req;
+
+ if (access->synchronized)
+ return 0;
+
+ if (fd == 0) {
+ struct sockaddr_nl sa;
+
+ fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0) {
+ snmp_log(LOG_ERR,"netsnmp_access_arp_load: netlink socket create error\n");
+ return -1;
+ }
+ access->arch_magic = (void *) fd;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.nl_family = AF_NETLINK;
+ sa.nl_groups = RTMGRP_NEIGH;
+ if (bind(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
+ snmp_log(LOG_ERR,"netsnmp_access_arp_load: netlink bind failed\n");
+ return -1;
+ }
+
+ if (register_readfd(fd, netsnmp_access_arp_read_netlink, access) != 0) {
+ snmp_log(LOG_ERR,"netsnmp_access_arp_load: error registering netlink socket\n");
+ return -1;
+ }
+ }
+
+ DEBUGMSGTL(("access:netlink:arp", "synchronizing arp table\n"));
+
+ access->generation++;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
+ req.n.nlmsg_type = RTM_GETNEIGH;
+ req.r.ndm_family = AF_UNSPEC;
+
+ r = send(fd, &req, req.n.nlmsg_len, 0);
+ if (r < 0) {
+ snmp_log(LOG_ERR,"netsnmp_access_arp_refresh: send failed\n");
+ return -1;
+ }
+
+ while (!access->synchronized)
+ netsnmp_access_arp_read_netlink(fd, access);
+ access->gc_hook(access);
+
+ return 0;
+}
+
+int netsnmp_access_arp_unload(netsnmp_arp_access *access)
+{
+ int fd;
+
+ access->synchronized = 0;
+ fd = (int) access->arch_magic;
+ if (fd > 0) {
+ unregister_readfd(fd);
+ close(fd);
+ access->arch_magic = NULL;
+ }
+ return 0;
+}
+
+static void netsnmp_access_arp_read_netlink(int fd, void *data)
+{
+ netsnmp_arp_access *access = (netsnmp_arp_access *) data;
+ netsnmp_arp_entry *entry;
+ char buf[16384];
+ struct nlmsghdr *h;
+ int r, len;
+
+ do {
+ r = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
+ if (r < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EAGAIN)
+ return;
+ snmp_log(LOG_ERR, "netlink buffer overrun\n");
+ access->synchronized = 0;
+ return;
+ }
+ } while (0);
+ len = r;
+
+ for (h = (struct nlmsghdr *) buf; NLMSG_OK(h, len); h = NLMSG_NEXT(h, len)) {
+ if (h->nlmsg_type == NLMSG_DONE) {
+ access->synchronized = 1;
+ continue;
+ }
+
+ entry = netsnmp_access_arp_entry_create();
+ if (NULL == entry)
+ break;
+
+ entry->generation = access->generation;
+ r = fillup_entry_info (entry, h);
+ if (r > 0) {
+ access->update_hook(access, entry);
+ } else {
+ if (r < 0) {
+ NETSNMP_LOGONCE((LOG_ERR, "filling entry info failed\n"));
+ DEBUGMSGTL(("access:netlink:arp", "filling entry info failed\n"));
+ }
+ netsnmp_access_arp_entry_free(entry);
+ }
+ }
+}
+
+static int
+fillup_entry_info(netsnmp_arp_entry *entry, struct nlmsghdr *nlmp)
+{
+ struct ndmsg *rtmp;
+ struct rtattr *tb[NDA_MAX + 1], *rta;
+ int length;
+
+ rtmp = (struct ndmsg *) NLMSG_DATA(nlmp);
+ switch (nlmp->nlmsg_type) {
+ case RTM_NEWNEIGH:
+ if (rtmp->ndm_state == NUD_FAILED)
+ entry->flags = NETSNMP_ACCESS_ARP_ENTRY_FLAG_DELETE;
+ else
+ entry->flags = 0;
+ break;
+ case RTM_DELNEIGH:
+ entry->flags = NETSNMP_ACCESS_ARP_ENTRY_FLAG_DELETE;
+ break;
+ case RTM_GETNEIGH:
+ return 0;
+ default:
+ DEBUGMSGTL(("access:netlink:arp",
+ "Wrong Netlink message type %d\n", nlmp->nlmsg_type));
+ return -1;
+ }
+
+ if (rtmp->ndm_state == NUD_NOARP) {
+ /* NUD_NOARP is for broadcast addresses and similar,
+ * drop them silently */
+ return 0;
+ }
+
+ memset(tb, 0, sizeof(struct rtattr *) * (NDA_MAX + 1));
+ length = nlmp->nlmsg_len - NLMSG_LENGTH(sizeof(*rtmp));
+ rta = ((struct rtattr *) (((char *) (rtmp)) + NLMSG_ALIGN(sizeof(struct ndmsg))));
+ while (RTA_OK(rta, length)) {
+ if (rta->rta_type <= NDA_MAX)
+ tb[rta->rta_type] = rta;
+ rta = RTA_NEXT(rta, length);
+ }
+
+ /*
+ * Fill up the index and addresses
+ */
+ entry->if_index = rtmp->ndm_ifindex;
+ if (tb[NDA_DST]) {
+ entry->arp_ipaddress_len = RTA_PAYLOAD(tb[NDA_DST]);
+ if (entry->arp_ipaddress_len > sizeof(entry->arp_ipaddress)) {
+ snmp_log(LOG_ERR, "netlink ip address length %d is too long\n",
+ entry->arp_ipaddress_len);
+ return -1;
+ }
+ memcpy(entry->arp_ipaddress, RTA_DATA(tb[NDA_DST]),
+ entry->arp_ipaddress_len);
+ }
+ if (tb[NDA_LLADDR]) {
+ entry->arp_physaddress_len = RTA_PAYLOAD(tb[NDA_LLADDR]);
+ if (entry->arp_physaddress_len > sizeof(entry->arp_physaddress)) {
+ snmp_log(LOG_ERR, "netlink hw address length %d is too long\n",
+ entry->arp_physaddress_len);
+ return -1;
+ }
+ memcpy(entry->arp_physaddress, RTA_DATA(tb[NDA_LLADDR]),
+ entry->arp_physaddress_len);
+ }
+
+ switch (rtmp->ndm_state) {
+ case NUD_INCOMPLETE:
+ entry->arp_state = INETNETTOMEDIASTATE_INCOMPLETE;
+ break;
+ case NUD_REACHABLE:
+ case NUD_PERMANENT:
+ entry->arp_state = INETNETTOMEDIASTATE_REACHABLE;
+ break;
+ case NUD_STALE:
+ entry->arp_state = INETNETTOMEDIASTATE_STALE;
+ break;
+ case NUD_DELAY:
+ entry->arp_state = INETNETTOMEDIASTATE_DELAY;
+ break;
+ case NUD_PROBE:
+ entry->arp_state = INETNETTOMEDIASTATE_PROBE;
+ break;
+ case NUD_FAILED:
+ entry->arp_state = INETNETTOMEDIASTATE_INVALID;
+ break;
+ case NUD_NONE:
+ entry->arp_state = INETNETTOMEDIASTATE_UNKNOWN;
+ break;
+ }
+
+ switch (rtmp->ndm_state) {
+ case NUD_INCOMPLETE:
+ case NUD_FAILED:
+ case NUD_NONE:
+ entry->arp_type = INETNETTOMEDIATYPE_INVALID;
+ break;
+ case NUD_REACHABLE:
+ case NUD_STALE:
+ case NUD_DELAY:
+ case NUD_PROBE:
+ entry->arp_type = INETNETTOMEDIATYPE_DYNAMIC;
+ break;
+ case NUD_PERMANENT:
+ entry->arp_type = INETNETTOMEDIATYPE_STATIC;
+ break;
+ default:
+ entry->arp_type = INETNETTOMEDIATYPE_LOCAL;
+ break;
+ }
+
+ return 1;
+}
Index: agent/mibgroup/ip-mib/data_access/arp_linuxproc.c
===================================================================
--- agent/mibgroup/ip-mib/data_access/arp_linuxproc.c (revision 0)
+++ agent/mibgroup/ip-mib/data_access/arp_linuxproc.c (revision 0)
@@ -0,0 +1,212 @@
+/*
+ * Interface MIB architecture support
+ */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include <net-snmp/data_access/arp.h>
+#include <net-snmp/data_access/interface.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if_arp.h>
+#include <arpa/inet.h>
+#include <linux/types.h>
+#include <asm/types.h>
+
+static int _load_v4(netsnmp_arp_access *access);
+
+netsnmp_arp_access *
+netsnmp_access_arp_create(u_int init_flags,
+ NetsnmpAccessArpUpdate *update_hook,
+ NetsnmpAccessArpGC *gc_hook,
+ int *cache_timeout, int *cache_flags)
+{
+ netsnmp_arp_access *access;
+
+ access = SNMP_MALLOC_TYPEDEF(netsnmp_arp_access);
+ if (NULL == access) {
+ snmp_log(LOG_ERR,"malloc error in netsnmp_access_arp_create\n");
+ return NULL;
+ }
+
+ access->arch_magic = NULL;
+ access->magic = NULL;
+ access->update_hook = update_hook;
+ access->gc_hook = gc_hook;
+ access->synchronized = 0;
+
+ if (cache_timeout != NULL)
+ *cache_timeout = 5;
+ if (cache_flags != NULL)
+ *cache_flags |= NETSNMP_CACHE_DONT_FREE_BEFORE_LOAD
+ | NETSNMP_CACHE_AUTO_RELOAD;
+
+ return access;
+}
+
+int netsnmp_access_arp_delete(netsnmp_arp_access *access)
+{
+ if (NULL == access)
+ return 0;
+
+ netsnmp_access_arp_unload(access);
+ free(access);
+
+ return 0;
+}
+
+int netsnmp_access_arp_load(netsnmp_arp_access *access)
+{
+ int rc = 0;
+
+ access->generation++;
+ rc =_load_v4(access);
+ access->gc_hook(access);
+ access->synchronized = (rc == 0);
+
+ return rc;
+}
+
+int netsnmp_access_arp_unload(netsnmp_arp_access *access)
+{
+ access->synchronized = 0;
+
+ return 0;
+}
+
+/**
+ */
+static int
+_load_v4(netsnmp_arp_access *access)
+{
+ FILE *in;
+ char line[128];
+ int rc = 0;
+ netsnmp_arp_entry *entry;
+ char arp[3*NETSNMP_ACCESS_ARP_PHYSADDR_BUF_SIZE+1];
+ char *arp_token;
+ int i;
+
+ netsnmp_assert(NULL != access);
+
+#define PROCFILE "/proc/net/arp"
+ if (!(in = fopen(PROCFILE, "r"))) {
+ snmp_log(LOG_DEBUG,"could not open " PROCFILE "\n");
+ return -2;
+ }
+
+ /*
+ * Get rid of the header line
+ */
+ fgets(line, sizeof(line), in);
+
+ /*
+ * IP address | HW | Flag | HW address | Mask | Device
+ * 192.168.1.4 0x1 0x2 00:40:63:CC:1C:8C * eth0
+ */
+ while (fgets(line, sizeof(line), in)) {
+
+ int za, zb, zc, zd;
+ unsigned int tmp_flags;
+ char ifname[21];
+
+ rc = sscanf(line,
+ "%d.%d.%d.%d 0x%*x 0x%x %96s %*[^ ] %20s\n",
+ &za, &zb, &zc, &zd, &tmp_flags, arp, ifname);
+ if (7 != rc) {
+ snmp_log(LOG_ERR, PROCFILE " data format error (%d!=12)\n", rc);
+ snmp_log(LOG_ERR, " line ==|%s|\n", line);
+ continue;
+ }
+ DEBUGMSGTL(("access:arp:container",
+ "ip addr %d.%d.%d.%d, flags 0x%X, hw addr "
+ "%s, name %s\n",
+ za,zb,zc,zd, tmp_flags, arp, ifname ));
+
+ /*
+ */
+ entry = netsnmp_access_arp_entry_create();
+ if(NULL == entry) {
+ rc = -3;
+ break;
+ }
+
+ /*
+ * look up ifIndex
+ */
+ entry->generation = access->generation;
+ entry->if_index = netsnmp_access_interface_index_find(ifname);
+ if(0 == entry->if_index) {
+ snmp_log(LOG_ERR,"couldn't find ifIndex for '%s', skipping\n",
+ ifname);
+ netsnmp_access_arp_entry_free(entry);
+ continue;
+ }
+
+ /*
+ * now that we've passed all the possible 'continue', assign
+ * index offset.
+ */
+ //entry->ns_arp_index = ++idx_offset;
+
+ /*
+ * parse ip addr
+ */
+ entry->arp_ipaddress[0] = za;
+ entry->arp_ipaddress[1] = zb;
+ entry->arp_ipaddress[2] = zc;
+ entry->arp_ipaddress[3] = zd;
+ entry->arp_ipaddress_len = 4;
+
+ /*
+ * parse hw addr
+ */
+ for (arp_token = strtok(arp, ":"), i=0; arp_token != NULL; arp_token = strtok(NULL, ":"), i++) {
+ entry->arp_physaddress[i] = strtol(arp_token, NULL, 16);
+ }
+ entry->arp_physaddress_len = i;
+
+ /*
+ * what can we do with hw? from arp manpage:
+
+ default value of this parameter is ether (i.e. hardware code
+ 0x01 for IEEE 802.3 10Mbps Ethernet). Other values might
+ include network technologies such as ARCnet (arcnet) , PROnet
+ (pronet) , AX.25 (ax25) and NET/ROM (netrom).
+ */
+
+ /*
+ * parse mask
+ */
+ /* xxx-rks: what is mask? how to interpret '*'? */
+
+
+ /*
+ * process type
+ */
+ if(tmp_flags & ATF_PERM)
+ entry->arp_type = INETNETTOMEDIATYPE_STATIC;
+ else
+ entry->arp_type = INETNETTOMEDIATYPE_DYNAMIC;
+
+ /*
+ * process status
+ * if flags are 0, we can't tell the difference between
+ * stale or incomplete.
+ */
+ if(tmp_flags & ATF_COM)
+ entry->arp_state = INETNETTOMEDIASTATE_REACHABLE;
+ else
+ entry->arp_state = INETNETTOMEDIASTATE_UNKNOWN;
+
+ /*
+ * add entry to container
+ */
+ access->update_hook(access, entry);
+ }
+
+ fclose(in);
+ return 0;
+}
Index: agent/mibgroup/ip-mib/data_access/arp.h
===================================================================
--- agent/mibgroup/ip-mib/data_access/arp.h (revision 19662)
+++ agent/mibgroup/ip-mib/data_access/arp.h (working copy)
@@ -18,8 +18,10 @@
* be handled in the *_hpux.h header file.
*/
config_require(ip-mib/data_access/arp_common)
-#if defined( linux )
-config_require(ip-mib/data_access/arp_linux)
+#if defined( HAVE_LINUX_RTNETLINK_H )
+config_require(ip-mib/data_access/arp_netlink)
+#elif defined( linux )
+config_require(ip-mib/data_access/arp_linuxproc)
#else
/*
* couldn't determine the correct file!
Index: agent/mibgroup/ip-mib/data_access/arp_common.c
===================================================================
--- agent/mibgroup/ip-mib/data_access/arp_common.c (revision 19662)
+++ agent/mibgroup/ip-mib/data_access/arp_common.c (working copy)
@@ -11,102 +11,6 @@
/**---------------------------------------------------------------------*/
/*
- * local static prototypes
- */
-static void _access_arp_entry_release(netsnmp_arp_entry * entry,
- void *unused);
-
-/**---------------------------------------------------------------------*/
-/*
- * external per-architecture functions prototypes
- *
- * These shouldn't be called by the general public, so they aren't in
- * the header file.
- */
-extern int
-netsnmp_access_arp_container_arch_load(netsnmp_container* container,
- u_int load_flags);
-
-
-/**---------------------------------------------------------------------*/
-/*
- * container functions
- */
-/**
- */
-netsnmp_container *
-netsnmp_access_arp_container_init(u_int flags)
-{
- netsnmp_container *container1;
-
- DEBUGMSGTL(("access:arp:container", "init\n"));
-
- /*
- * create the containers. one indexed by ifIndex, the other
- * indexed by ifName.
- */
- container1 = netsnmp_container_find("access_arp:table_container");
- if (NULL == container1)
- return NULL;
- return container1;
-}
-
-/**
- * @retval NULL error
- * @retval !NULL pointer to container
- */
-netsnmp_container*
-netsnmp_access_arp_container_load(netsnmp_container* container, u_int load_flags)
-{
- int rc;
-
- DEBUGMSGTL(("access:arp:container", "load\n"));
-
- if (NULL == container) {
- container = netsnmp_container_find("access:arp:table_container");
- if (container)
- container->container_name = strdup("arp");
- }
- if (NULL == container) {
- snmp_log(LOG_ERR, "no container specified/found for access_arp\n");
- return NULL;
- }
-
- rc = netsnmp_access_arp_container_arch_load(container, load_flags);
- if (0 != rc) {
- netsnmp_access_arp_container_free(container,
- NETSNMP_ACCESS_ARP_FREE_NOFLAGS);
- container = NULL;
- }
-
- return container;
-}
-
-void
-netsnmp_access_arp_container_free(netsnmp_container *container, u_int free_flags)
-{
- DEBUGMSGTL(("access:arp:container", "free\n"));
-
- if (NULL == container) {
- snmp_log(LOG_ERR, "invalid container for netsnmp_access_arp_free\n");
- return;
- }
-
- if(! (free_flags & NETSNMP_ACCESS_ARP_FREE_DONT_CLEAR)) {
- /*
- * free all items.
- */
- CONTAINER_CLEAR(container,
- (netsnmp_container_obj_func*)_access_arp_entry_release,
- NULL);
- }
-
- if(! (free_flags & NETSNMP_ACCESS_ARP_FREE_KEEP_CONTAINER))
- CONTAINER_FREE(container);
-}
-
-/**---------------------------------------------------------------------*/
-/*
* arp_entry functions
*/
/**
@@ -137,14 +41,6 @@
*/
/**
- */
-void
-_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.
*/
@@ -153,6 +49,7 @@
{
int modified = 0;
+ entry->generation = new_data->generation;
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;
Index: agent/helpers/cache_handler.c
===================================================================
--- agent/helpers/cache_handler.c (revision 19662)
+++ agent/helpers/cache_handler.c (working copy)
@@ -25,7 +25,7 @@
static int cache_outstanding_valid = 0;
static int _cache_load( netsnmp_cache *cache );
-#define CACHE_RELEASE_FREQUENCY 60 /* Check for expired caches every 60s */
+#define CACHE_RELEASE_FREQUENCY 10 /* Check for expired caches every 60s */
void release_cached_resources(unsigned int regNo,
void *clientargs);
@@ -79,7 +79,13 @@
* the cache when it expires. This is useful for keeping the cache fresh,
* even in the absence of incoming snmp requests.
*
+ * If NETSNMP_DYNAMIC_TIMEOUT is set, the expiry timer will be reset
+ * on each cache access. In practice the 'timeout' becomes a timer
+ * which triggers when the cache is no longer needed. This is useful
+ * if the cache is automatically kept synchronized: e.g. by receiving
+ * change notifications from Netlink, inotify or similar.
*
+ *
* Here are some suggestions for some common situations.
*
* Cached File:
@@ -110,6 +116,13 @@
* NETSNMP_CACHE_DONT_AUTO_RELEASE
* NETSNMP_CACHE_AUTO_RELOAD
*
+ * Dynamically updated, unloaded after timeout:
+ * If the cache is kept up to date dynamically by listening for
+ * change notifications somehow, but it should not be in memory
+ * if it's not needed. Set the following flag:
+ *
+ * NETSNMP_CACHE_DYNAMIC_TIMEOUT
+ *
* @{
*/
@@ -621,6 +634,8 @@
netsnmp_request_set_error_all(requests, SNMP_ERR_GENERR);
return SNMP_ERR_GENERR;
}
+ if (cache->flags & NETSNMP_CACHE_DYNAMIC_TIMEOUT)
+ atime_setMarker(cache->timestamp);
return SNMP_ERR_NOERROR;
}
------------------------------------------------------------------------------
Increase Visibility of Your 3D Game App & Earn a Chance To Win $500!
Tap into the largest installed PC base & get more eyes on your game by
optimizing for Intel(R) Graphics Technology. Get started today with the
Intel(R) Software Partner Program. Five $500 cash prizes are up for grabs.
http://p.sf.net/sfu/intelisp-dev2dev
_______________________________________________
Net-snmp-coders mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders