On 11/19/2010 03:06 PM, Robert Story wrote:
> On Thu, 18 Nov 2010 10:58:48 +0200 Timo wrote:
> TT> Gets only container, and I can't associate my context data with it
> TT> easily. This is called from inetNetToMediaTable_interface.c which says
> TT> in big letters "NOT USER EDITABLE CODE". So I can't modify the proto
> TT> type either.
> TT> 
> TT> So I should either modify mib2c to allow passing additional data with
> TT> it, or make inetNetToMediaTable not use mib2c anymore. Either does not
> TT> sound nice.
> 
> I'd just store your context pointer as a static pointer in
> inetNetToMediaTable_data_access.c.

Yes, that's the obviously easiest thing to do. I just consider static
pointers to be bad practice. I guess it can do for now.

As all projects, this one is late too. I've been busy with other stuff.
Like everyone is ;)

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.

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)
@@ -86,11 +86,13 @@
    u_long    arp_last_updated;   /* timeticks of last update */
 } netsnmp_arp_entry;
 
+#define NETSNMP_ACCESS_ARP_ENTRY_FLAG_DELETE 0x0001
 
 /**---------------------------------------------------------------------*/
 /*
  * ACCESS function prototypes
  */
+#if 0
 /*
  * ifcontainer init
  */
@@ -110,8 +112,33 @@
 #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;
+	NetsnmpAccessArpUpdate *update_hook;
+	NetsnmpAccessArpGC *gc_hook;
+};
+
+
+netsnmp_arp_access *
+netsnmp_access_arp_create(u_int init_flags, void *magic,
+			  NetsnmpAccessArpUpdate *update_hook,
+			  NetsnmpAccessArpGC *gc_hook);
+#define NETSNMP_ACCESS_ARP_CREATE_NOFLAGS             0x0000
+
+int netsnmp_access_arp_refresh(netsnmp_arp_access *access);
+
+int netsnmp_access_arp_delete(netsnmp_arp_access *access);
+
 /*
  * create/free a arp+entry
  */
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
@@ -195,7 +196,14 @@
 
         /* 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 */
@@ -240,14 +248,28 @@
 {
     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 */
 
+
+static void  _arp_hook_update(netsnmp_arp_access *access, netsnmp_arp_entry *entry)
+{
+    _add_or_update_arp_entry(entry, access->magic);
+}
+
+static void _arp_hook_enumerate(netsnmp_arp_access *access)
+{
+}
+
 /**
  * load initial data
  *
@@ -284,11 +306,27 @@
 int
 inetNetToMediaTable_container_load(netsnmp_container *container)
 {
+    DEBUGMSGTL(("verbose:inetNetToMediaTable:inetNetToMediaTable_cache_load", "called\n"));
+
+    if (NULL == arp_access) {
+        arp_access = netsnmp_access_arp_create(
+                               NETSNMP_ACCESS_ARP_CREATE_NOFLAGS,
+                               container,
+                               _arp_hook_update,
+                               _arp_hook_enumerate);
+        if (arp_access == NULL)
+            return MFD_ERROR;
+    }
+
+    if (netsnmp_access_arp_refresh(arp_access) < 0)
+        return MFD_ERROR;
+
+    return MFD_SUCCESS;
+
+#if 0
     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,
@@ -333,6 +371,7 @@
     DEBUGMSGT(("verbose:inetNetToMediaTable:inetNetToMediaTable_cache_load", "%" NETSNMP_PRIz "u records\n", CONTAINER_SIZE(container)));
 
     return MFD_SUCCESS;
+#endif
 }                               /* inetNetToMediaTable_container_load */
 
 /**
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,271 @@
+/*
+ *  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, void *magic,
+			  NetsnmpAccessArpUpdate *update_hook,
+			  NetsnmpAccessArpGC *gc_hook)
+{
+    netsnmp_arp_access *access;
+    struct sockaddr_nl sa;
+    int fd;
+
+    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->magic = magic;
+    access->update_hook = update_hook;
+    access->gc_hook = gc_hook;
+    access->synchronized = 0;
+
+    fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+    if (fd < 0) {
+        snmp_log(LOG_ERR,"netlink socket create error in netsnmp_access_arp_create\n");
+        netsnmp_access_arp_delete(access);
+        return NULL;
+    }
+    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_create: netlink bind failed\n");
+        netsnmp_access_arp_delete(access);
+        return NULL;
+    }
+
+    if (register_readfd(fd, netsnmp_access_arp_read_netlink, access) != 0) {
+        snmp_log(LOG_ERR,"netsnmp_prefix_listen: error registering netlink socket\n");
+        netsnmp_access_arp_delete(access);
+        return NULL;
+    }
+
+    return access;
+}
+
+int netsnmp_access_arp_refresh(netsnmp_arp_access *access)
+{
+    int r, fd = (int) access->arch_magic;
+    struct {
+        struct nlmsghdr n;
+        struct ndmsg r;
+    } req;
+
+    if (access->synchronized)
+        return 0;
+
+    DEBUGMSGTL(("access:netlink:arp", "synchronizing arp table\n"));
+
+    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);
+
+    return 0;
+}
+
+int netsnmp_access_arp_delete(netsnmp_arp_access *access)
+{
+    int fd;
+
+    if (NULL == access)
+        return 0;
+
+    fd = (int) access->arch_magic;
+    if (fd > 0) {
+         unregister_readfd(fd);
+         close(fd);
+    }
+    free(access);
+
+    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;
+
+         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.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.
  */
------------------------------------------------------------------------------
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
Net-snmp-coders@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders

Reply via email to