Greetings SNMP coders and users,

Every once in a while someone complains about having to wait for the 60 second timer to elapse before getting their 'linkUpDownNotifications'. The attached patch causes snmpd to register with the linux RT-NETLINK facility in order to be notified of link state changes. IP interfaces going up and down now generate traps immediately.

The linkUpDownNotifications snmpd.conf directive has been changed to use rt-netlink instead of the 60s timer, and a "-n" option has been added to the monitor directive in order to trigger it using netlink instead of a timed poll. The ifTable cache reload has also been changed to trigger on netlink message reception in addition to its own 30s timer.

Note that the netlink trigger method has not been generalized, and registers only for IP interface link activity.

Rate limiting:

A configuration directive was added to snmpd.conf to control the frequency with which link up down traps are generated.

     "netlinkTiggerRes <timeout in milliseconds>" default = 5000ms

(Netlink trigger resolution) specifies the minimum time allowed between consecutive link state traps for a single IP interface. For example, if a link changes state at t=0, a trap is generated immediately. If the same link changes state at t=1000ms, this is less than the trigger resolution of 5000 ms, and therefore a trap will not be generated. An event will, however, be scheduled for 5000-1000ms = 4000ms in the future, that will check link state and send traps if link states have changed since the last link state traps were transmitted.

If, instead of the same IP Link changing state, a different link changes state at t=1000ms, the timeout restriction would not apply, and a trap would be generated immediately.

My apologies ahead of time for the vintage of net-snmp that I've applied this to. The patch is relatively small, and should hopefully be easily adaptable to more recent versions.



Michael Leslie
--
RuggedCom Inc.
www.ruggedcom.com
Telephone: (905) 856-5288
Toll Free: 1-888-264-0006

************************
NOTICE OF CONFIDENTIALITY:
This e-mail and any attachments may contain confidential and privileged
information. If you are not the intended recipient, please notify the sender
immediately by return e-mail and delete this e-mail and any copies. Any
dissemination or use of this information by a person other than the intended
recipient is unauthorized and may be illegal.
************************

diff -Nur net-snmp-5.2.3.rr1/agent/helpers/cache_handler.c net-snmp-5.2.3.rr1.new/agent/helpers/cache_handler.c
--- net-snmp-5.2.3.rr1/agent/helpers/cache_handler.c	2006-01-25 11:28:10.000000000 -0500
+++ net-snmp-5.2.3.rr1.new/agent/helpers/cache_handler.c	2007-05-16 10:49:31.000000000 -0400
@@ -15,6 +15,10 @@
 #include <dmalloc.h>
 #endif
 
+#if HAVE_LINUX_RTNETLINK_H
+#include <mibgroup/disman/rtnetlinkTrigger.h>
+#endif
+
 static netsnmp_cache  *cache_head = NULL;
 static int             cache_outstanding_valid = 0;
 static int             _cache_load( netsnmp_cache *cache );
@@ -208,6 +212,10 @@
         return 0;
     }
 
+#if HAVE_LINUX_RTNETLINK_H
+    if (cache->flags & NETSNMP_CACHE_NETLINK_TRIGGER)
+        netlink_trigger_register_before(_timer_reload, cache);
+#endif
     cache->timer_id = snmp_alarm_register(cache->timeout, SA_REPEAT,
                                           _timer_reload, cache);
     if(0 == cache->timer_id) {
diff -Nur net-snmp-5.2.3.rr1/agent/mibgroup/disman/event-mib.h net-snmp-5.2.3.rr1.new/agent/mibgroup/disman/event-mib.h
--- net-snmp-5.2.3.rr1/agent/mibgroup/disman/event-mib.h	2002-12-04 19:32:52.000000000 -0500
+++ net-snmp-5.2.3.rr1.new/agent/mibgroup/disman/event-mib.h	2007-05-16 10:49:44.000000000 -0400
@@ -9,4 +9,5 @@
 config_require(disman/mteObjectsTable)
 config_require(disman/mteEventTable)
 config_require(disman/mteEventNotificationTable)
+config_require(disman/rtnetlinkTrigger)
 config_add_mib(DISMAN-EVENT-MIB)
diff -Nur net-snmp-5.2.3.rr1/agent/mibgroup/disman/mteEventTable.c net-snmp-5.2.3.rr1.new/agent/mibgroup/disman/mteEventTable.c
--- net-snmp-5.2.3.rr1/agent/mibgroup/disman/mteEventTable.c	2004-01-27 12:41:44.000000000 -0500
+++ net-snmp-5.2.3.rr1.new/agent/mibgroup/disman/mteEventTable.c	2007-05-16 10:50:01.000000000 -0400
@@ -116,11 +116,26 @@
 void
 parse_linkUpDownNotifications(const char *token, char *line) {
     if (strncmp(line, "y", 1) == 0) {
+
+        parse_notificationEvent("notificationEvent",
+		"linkUpTrap linkUp ifIndex ifAdminStatus ifOperStatus");
+        parse_notificationEvent("notificationEvent",
+		"linkDownTrap linkDown ifIndex ifAdminStatus ifOperStatus");
+
+        /* New netlink triggered method */
+        parse_simple_monitor("monitor",
+                             "-n -e linkUpTrap \"Generate linkUp\" ifOperStatus != 2");
+        parse_simple_monitor("monitor",
+                             "-n -e linkDownTrap \"Generate linkDown\" ifOperStatus == 2");
+
+    } else if (strncmp(line, "old", 3) == 0) {
+
         parse_notificationEvent("notificationEvent", "linkUpTrap   	 linkUp     ifIndex ifAdminStatus ifOperStatus");
         parse_notificationEvent("notificationEvent", "linkDownTrap 	 linkDown   ifIndex ifAdminStatus ifOperStatus");
 
         parse_simple_monitor("monitor", "-r 60 -e linkUpTrap \"Generate linkUp\" ifOperStatus != 2");
         parse_simple_monitor("monitor", "-r 60 -e linkDownTrap \"Generate linkDown\" ifOperStatus == 2");
+
     }
 }
 
diff -Nur net-snmp-5.2.3.rr1/agent/mibgroup/disman/mteTriggerTable.c net-snmp-5.2.3.rr1.new/agent/mibgroup/disman/mteTriggerTable.c
--- net-snmp-5.2.3.rr1/agent/mibgroup/disman/mteTriggerTable.c	2006-01-30 04:28:05.000000000 -0500
+++ net-snmp-5.2.3.rr1.new/agent/mibgroup/disman/mteTriggerTable.c	2007-05-16 10:50:21.000000000 -0400
@@ -36,6 +36,10 @@
 #include "mteEventTable.h"
 #include "mteObjectsTable.h"
 
+#if HAVE_LINUX_RTNETLINK_H
+#include "rtnetlinkTrigger.h"
+#endif
+
 /*
  * mteTriggerTable_variables_oid:
  *   this is the top level oid that we want to register under.  This
@@ -427,6 +431,13 @@
                 return;
             }
             break;
+#if HAVE_LINUX_RTNETLINK_H
+        case 'n':
+	  /* Use Netlink to trigger this event */
+	  StorageNew->mteTriggerNetlink = 1;
+	  StorageNew->mteTriggerFrequency = 0;
+	  break;
+#endif
         case 'u':
             if (cp) {
                 cp = copy_nword(cp, buf, sizeof(buf));
@@ -3295,7 +3306,7 @@
         snmp_alarm_unregister(clientreg);
         return;
     }
-    DEBUGMSGTL(("mteTriggertable", "Running trigger for %s/%s\n",
+    DEBUGMSGTL(("mteTriggerTable", "Running trigger for %s/%s\n",
                 item->mteOwner, item->mteTriggerName));
 
     next_oid = item->mteTriggerValueID;
@@ -3692,8 +3703,14 @@
     if (item->alarmreg)
         snmp_alarm_unregister(item->alarmreg);
 
+    if (item->mteTriggerNetlink) {
+        DEBUGMSGTL(("mteTriggerTable", "Enabling netlink trigger for %s/%s\n",
+		    item->mteOwner, item->mteTriggerName));
+	netlink_trigger_register (mte_run_trigger, item);
+    }
+
     if (item->mteTriggerFrequency > 0) {
-        DEBUGMSGTL(("mteTriggertable", "Enabling trigger for %s/%s @ %u\n",
+        DEBUGMSGTL(("mteTriggerTable", "Enabling trigger for %s/%s @ %u\n",
                     item->mteOwner, item->mteTriggerName,
                     item->mteTriggerFrequency));
         item->alarmreg =
@@ -3709,7 +3726,7 @@
         return;
 
     if (item->alarmreg) {
-        DEBUGMSGTL(("mteTriggertable", "Disabling trigger for %s/%s\n",
+        DEBUGMSGTL(("mteTriggerTable", "Disabling trigger for %s/%s\n",
                     item->mteOwner, item->mteTriggerName));
         snmp_alarm_unregister(item->alarmreg);
         item->alarmreg = 0;
diff -Nur net-snmp-5.2.3.rr1/agent/mibgroup/disman/mteTriggerTable.h net-snmp-5.2.3.rr1.new/agent/mibgroup/disman/mteTriggerTable.h
--- net-snmp-5.2.3.rr1/agent/mibgroup/disman/mteTriggerTable.h	2002-12-16 17:42:14.000000000 -0500
+++ net-snmp-5.2.3.rr1.new/agent/mibgroup/disman/mteTriggerTable.h	2007-05-16 10:50:30.000000000 -0400
@@ -38,6 +38,7 @@
          char           *mteTriggerContextName;
          size_t          mteTriggerContextNameLen;
          long            mteTriggerContextNameWildcard;
+         long            mteTriggerNetlink;
          unsigned long   mteTriggerFrequency;
          char           *mteTriggerObjectsOwner;
          size_t          mteTriggerObjectsOwnerLen;
diff -Nur net-snmp-5.2.3.rr1/agent/mibgroup/disman/rtnetlinkTrigger.c net-snmp-5.2.3.rr1.new/agent/mibgroup/disman/rtnetlinkTrigger.c
--- net-snmp-5.2.3.rr1/agent/mibgroup/disman/rtnetlinkTrigger.c	1969-12-31 19:00:00.000000000 -0500
+++ net-snmp-5.2.3.rr1.new/agent/mibgroup/disman/rtnetlinkTrigger.c	2007-05-16 10:50:37.000000000 -0400
@@ -0,0 +1,490 @@
+/*
+ * rtnetlink.c
+ */
+/*
+ * rtnetlink.c provides support for the linux NETLINK mechanism
+ * for immediate triggering upon network interface link status change
+ */
+/*
+ * Copyright Ruggedcom, 2007 - Michael Leslie
+ */
+
+
+
+/**** Necessary includes: ***************************************************/
+
+/* #include <stdio.h> */
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <sys/time.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+
+#define RTNETLINK_DECLS
+#include "rtnetlinkTrigger.h"
+
+/* for print_if_flags(): */
+#if defined(NETLINK_DEBUG)
+#  include <net/if.h>
+#endif
+
+/* #include <net-snmp/library/snmp_logging.h> */
+#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/library/snmp_alarm.h>
+
+
+/****************************************************************************/
+
+/**** local declarations: ****/
+
+int err;
+
+struct sockaddr_nl socket_address;
+
+#if defined(NETLINK_DEBUG)
+void print_if_flags(unsigned int flags);
+void dump_msghdr(struct msghdr *msghdr);
+#endif
+
+
+/* rate limiting declarations: */
+#define DEFAULT_NETLINK_TRIGGER_RESOLUTION  5000  /* milliseconds */
+int netlinkTriggerResolution = DEFAULT_NETLINK_TRIGGER_RESOLUTION;
+int timeval_exceeds_by (struct timeval *later,
+			struct timeval *earlier, int delta);
+void parse_netlinkTriggerRes(const char *token, char *line);
+
+
+/* trigger_history: */
+int            last_trigger_if_index;
+struct timeval last_trigger_time;
+
+static int snmp_alarm_registration = 0;
+
+static int netlink_timer_expired (void);
+static int trigger_reenable_seconds (void);
+
+static void run_netlink_trigger_list(unsigned int unused_reg, void *unused_arg);
+
+
+/****************************************************************************/
+
+/*
+ * void init_rtnetlink(void)
+ *
+ * connects to the kernel NETLINK socket to subscribe
+ * to NETLINK_ROUTE messages. Sets rtnetlink_fd and
+ * returns zero on success.
+ */
+void
+init_rtnetlinkTrigger()
+{
+  int fd;
+
+  fd = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (fd < 0) {
+    snmp_log_perror ("Error opening netlink socket");
+    return;
+  }
+
+  socket_address.nl_family = AF_NETLINK;
+  socket_address.nl_pid    = getpid();
+  socket_address.nl_groups = RTMGRP_LINK;
+
+  if (bind (fd, (struct sockaddr *)&socket_address,
+	    sizeof (socket_address)) != 0) {
+    snmp_log_perror ("Error binding to netlink socket");
+    return;
+  }
+  rtnetlink_fd = fd;
+
+  snmpd_register_config_handler("netlinkTiggerRes",
+			parse_netlinkTriggerRes, NULL, 
+			"netlinkTiggerRes (netlink trigger resolution in ms)");
+}
+
+void
+parse_netlinkTriggerRes(const char *token, char *line) {
+    int n;
+
+    n = sscanf (line, "%d", &netlinkTriggerResolution);
+
+    if (n < 1)
+        DEBUGMSGTL(("rtnetlink_trigger",
+	    "failed to parse trigger resolution from: \"%s\"\n", line));
+
+}
+
+static unsigned int regnum = 1;
+static struct rtnetlink_trigger *rtnetlink_trigger_list = NULL;
+
+/*
+ * unsigned int netlink_trigger_register()
+ *
+ * adds a callback / void *argument to the (end of the) netlink
+ * trigger table.
+ */
+unsigned int
+netlink_trigger_register (rtnetlinkCallback *callback, void *clientarg)
+{
+  struct rtnetlink_trigger **nt_pptr;
+
+  if (rtnetlink_trigger_list != NULL) {
+    for (nt_pptr = &rtnetlink_trigger_list; (*nt_pptr) != NULL;
+	 nt_pptr = &((*nt_pptr)->next));
+  } else {
+    nt_pptr = &rtnetlink_trigger_list;
+  }
+
+  *nt_pptr = SNMP_MALLOC_STRUCT(rtnetlink_trigger);
+  if (*nt_pptr == NULL)
+    return 0;
+
+  (*nt_pptr)->clientarg = clientarg;
+  (*nt_pptr)->callback  = callback;
+  (*nt_pptr)->clientreg = regnum++;
+  (*nt_pptr)->next = NULL;
+
+  DEBUGMSGTL(("rtnetlink_trigger",
+	      "registered rtnetlink trigger %d\n", (*nt_pptr)->clientreg));
+
+  return (*nt_pptr)->clientreg;
+}
+
+
+/*
+ * unsigned int netlink_trigger_register_before()
+ *
+ * adds a callback / void *argument to the (beginning of the) netlink
+ * trigger table.
+ */
+unsigned int
+netlink_trigger_register_before (rtnetlinkCallback *callback, void *clientarg)
+{
+  struct rtnetlink_trigger *nt_pptr;
+
+  nt_pptr = SNMP_MALLOC_STRUCT(rtnetlink_trigger);
+  if (nt_pptr == NULL)
+    return 0;
+
+  if (rtnetlink_trigger_list != NULL) {
+    nt_pptr->next = rtnetlink_trigger_list;
+    rtnetlink_trigger_list = nt_pptr;
+  } else {
+    rtnetlink_trigger_list = nt_pptr;
+    nt_pptr->next = NULL;
+  }
+
+  nt_pptr->clientarg = clientarg;
+  nt_pptr->callback  = callback;
+  nt_pptr->clientreg = regnum++;
+
+  DEBUGMSGTL(("rtnetlink_trigger",
+	      "registered rtnetlink trigger %d\n", nt_pptr->clientreg));
+
+  return nt_pptr->clientreg;
+}
+
+
+
+void run_netlink_triggers(int fd)
+{
+    struct trigger_history   *trig_hist;
+    int                       if_index;
+    struct timeval            now;
+
+    /* FOR NOW we do not use the data in the netlink message itself
+     * to update the data in the MIB. It is only used as an alternative
+     * trigger to the existing timeout-based alarm system.
+     *
+     * An intermediate enhancement might be to register different triggers
+     * based on different OIDs => different RTNETLINK groups, => different
+     * rtnetlink file descriptors.
+     *
+     * Ultimately, we should also parse the desired data from the netlink
+     * communication, update the MIB, and continue along with notification
+     * processing directly.
+     *
+     * Simply dequeue the netlink message, saving only the interface index:
+     */
+    if_index = read_netlink_message (fd);
+
+    if (rtnetlink_trigger_list == NULL)
+      return;
+
+    if (if_index == -1)
+      /* failed to parse interface index from netlink message
+       * abort cache refresh and trap generation */
+      return;
+
+    if (if_index == last_trigger_if_index) {
+        if (!netlink_timer_expired()) {
+	  /* Schedule a netlink trigger after expiry. Note that there will
+	   * be no corresponding netlink message receipt at that time.
+	   */
+	  DEBUGMSGTL(("rtnetlink_trigger", "netlink timer pending.\n"));
+
+	  if (trig_hist && !snmp_alarm_registration) {
+	      unsigned int  when;
+
+	      when = trigger_reenable_seconds ();
+	      DEBUGMSGTL(("rtnetlink_trigger",
+			  "register alarm in %d seconds.\n", when));
+	      snmp_alarm_registration = 
+		snmp_alarm_register (when, 0, run_netlink_trigger_list, NULL);
+	  }
+	  return;
+	}
+    }
+
+    gettimeofday (&now, NULL);
+    memcpy (&last_trigger_time, &now, sizeof (struct timeval));
+    last_trigger_if_index = if_index;
+    run_netlink_trigger_list(0, NULL);
+}
+
+
+/*
+ * Run through and call the list of netlink triggered functions.
+ * The arguments are only there in order to satisfy the ability to
+ * register the function with snmp_alarm_register()
+ */
+static void
+run_netlink_trigger_list(unsigned int unused_reg, void *unused_arg)
+{
+    struct rtnetlink_trigger *trig = NULL;
+    unsigned int              clientreg;
+
+    snmp_alarm_registration = 0;
+    for (trig = rtnetlink_trigger_list; trig != NULL; trig = trig->next) {
+    clientreg = trig->clientreg;
+    DEBUGMSGTL(("rtnetlink_trigger", "run trigger %d\n", clientreg));
+    if (trig->callback != NULL)
+      (*(trig->callback)) (trig->clientreg, trig->clientarg);
+    DEBUGMSGTL(("rtnetlink_trigger", "trigger %d completed\n", clientreg));
+  }
+}
+
+
+
+
+/*
+ * int netlink_timer_expired ()
+ *
+ * checks the previous trigger time, 'last_trigger_time'
+ * to see whether the allowed time (netlinkTriggerResolution)
+ * has elapsed, in which case it returns 1.
+ *
+ */
+static int netlink_timer_expired (void)
+{
+  struct timeval trigger_time;
+ 
+  if (netlinkTriggerResolution <= 10 /* ms */)
+    return 1;
+
+  gettimeofday (&trigger_time, NULL);
+
+  if (timeval_exceeds_by (&trigger_time, &last_trigger_time,
+			     netlinkTriggerResolution)) {
+      memcpy (&last_trigger_time, &trigger_time, sizeof (struct timeval));
+      return (1);
+  }
+
+  /* otherwise, the required time has not yet elapsed */
+  return (0);
+}
+
+
+
+
+/* Return 1 if 'later' exceeds 'earlier' by 'delta' milliseconds or more */
+int timeval_exceeds_by (struct timeval *later,
+			struct timeval *earlier, int delta)
+{
+    int delta_s, delta_us;
+
+    if (timercmp(earlier, later, >))
+        return 0;
+
+    delta_s  = later->tv_sec  - earlier->tv_sec;
+    delta_us = later->tv_usec - earlier->tv_usec;
+
+    /* to remove doubt and complication, 'normalize' the delta: */
+    if (delta_us > 1000000) {
+        delta_s += (delta_us / 1000000);
+        delta_us = (delta_us % 1000000);
+    }
+
+    if (delta_s > (delta / 1000))
+        return (1);
+
+    if ((delta_s * 1000) + (delta_us / 1000) > delta)
+        return (1);
+
+    return (0);
+}
+
+
+/* Return the number of seconds till the interface trigger will
+ * be reenabled. Used to schedule a snmp_alarm
+ */
+int trigger_reenable_seconds ()
+{
+  struct timeval now, *last;
+  int            delta; /* in seconds */
+
+  gettimeofday (&now, NULL);
+
+  last = &last_trigger_time;
+
+  delta  =  now.tv_sec - last->tv_sec;
+  delta += (now.tv_usec - last->tv_usec)/1000000;
+
+  delta = (netlinkTriggerResolution/1000 - delta);
+  if (delta < 0)
+    delta = 0;
+
+  return (delta);
+}
+
+
+
+
+
+/* Read netling message, keeping (and returning) ONLY the interface
+ * index (according to the kernel. This probably does not reflect
+ * SNMP index numbering. */
+int read_netlink_message (int fd)
+{
+  struct msghdr     msghdr;
+  struct iovec      iov;
+  struct nlmsghdr  *nlhdr;
+  struct ifinfomsg *ifh;
+  int    i, err, flags, msg_length, if_index;
+  char   tmp_buf[sizeof(struct nlmsghdr)];
+
+  memset (&msghdr, 0, sizeof (msghdr));
+
+  iov.iov_base      = &tmp_buf; /* just large enough to see msg_len */
+  iov.iov_len       = sizeof(struct nlmsghdr);
+  msghdr.msg_iov    = &iov;
+  msghdr.msg_iovlen = 1; /* element in the vector */
+
+
+  /* peek first to find the message's size: */
+  flags = MSG_PEEK;
+
+  for (i=0;i<2;i++) {
+    err = recvmsg(fd, &msghdr, flags);
+
+    if (err < 0) {
+      perror ("recvmsg");
+#if defined(NETLINK_DEBUG)
+      dump_msghdr(&msghdr);
+#endif
+      return (-1);
+    
+    } else {
+      nlhdr = (struct nlmsghdr *)(msghdr.msg_iov->iov_base);
+
+      if (msghdr.msg_flags & MSG_TRUNC) {
+	msg_length = nlhdr->nlmsg_len;
+	iov.iov_base = malloc (msg_length);
+	if (iov.iov_base == NULL) {
+	  perror ("allocating msghdr.msg_iov");
+	  exit (-1);
+	}
+	iov.iov_len = msg_length;
+
+      }
+    }
+    flags=0;
+  }
+
+  nlhdr = (struct nlmsghdr *)(msghdr.msg_iov->iov_base);
+  ifh   = (struct ifinfomsg *)((unsigned char *) nlhdr + NLMSG_HDRLEN);
+  
+  if_index = ifh->ifi_index;
+
+#if defined(NETLINK_DEBUG)
+
+  printf ("Length of message including header = %i\n", nlhdr->nlmsg_len);
+  printf ("Type of message content = 0x%04x\n",        nlhdr->nlmsg_type);
+  printf ("Additional flags = 0x%04x\n",               nlhdr->nlmsg_flags);
+  printf ("Sequence number = %i\n",                    nlhdr->nlmsg_seq);
+  printf ("PID of the sending process = %i\n",         nlhdr->nlmsg_pid);
+	
+  ifh = (struct ifinfomsg *)((unsigned char *) nlhdr + NLMSG_HDRLEN);
+
+  printf ("ifi_family  = 0x%02x\n", ifh->ifi_family);
+  printf ("ifi_type    = 0x%04x\n", ifh->ifi_type);
+  printf ("Link index  = %i\n",     ifh->ifi_index);
+  printf ("Flags       = 0x%08x: ", ifh->ifi_flags);
+  print_if_flags(ifh->ifi_flags); puts("\n");
+  printf ("Change mask = 0x%08x\n", ifh->ifi_change);
+
+#endif
+
+  free (iov.iov_base);
+
+  return (if_index);
+}
+
+#if defined(NETLINK_DEBUG)
+
+void print_if_flags(unsigned int flags)
+{
+  if (flags & IFF_UP)          printf (" IFF_UP");
+  if (flags & IFF_BROADCAST)   printf (" IFF_BROADCAST");
+  if (flags & IFF_DEBUG)       printf (" IFF_DEBUG");
+  if (flags & IFF_LOOPBACK)    printf (" IFF_LOOPBACK");
+  if (flags & IFF_POINTOPOINT) printf (" IFF_POINTOPOINT");
+  if (flags & IFF_NOTRAILERS)  printf (" IFF_NOTRAILERS");
+  if (flags & IFF_RUNNING)     printf (" IFF_RUNNING");
+  if (flags & IFF_NOARP)       printf (" IFF_NOARP");
+  if (flags & IFF_PROMISC)     printf (" IFF_PROMISC");
+  if (flags & IFF_ALLMULTI)    printf (" IFF_ALLMULTI");
+  if (flags & IFF_MASTER)      printf (" IFF_MASTER");
+  if (flags & IFF_SLAVE)       printf (" IFF_SLAVE");
+  if (flags & IFF_MULTICAST)   printf (" IFF_MULTICAST");
+  if (flags & IFF_PORTSEL)     printf (" IFF_PORTSEL");
+  if (flags & IFF_AUTOMEDIA)   printf (" IFF_AUTOMEDIA");
+  /* if (flags & IFF_DYNAMIC)     printf (" IFF_DYNAMIC"); */
+  /* if (flags & IFF_LOWER_UP)    printf (" LOWER_UP"); */
+  /* if (flags & IFF_DORMANT)     printf (" IFF_DORMANT"); */
+}
+
+
+
+void dump_msghdr(struct msghdr *msghdr) {
+  /* printf ("msg_iovlen     = %i\n",     msghdr->msg_iovlen); */
+  printf ("msg_controllen = %i\n",     msghdr->msg_controllen);
+
+  printf ("msg_flags      = 0x%08x: ", msghdr->msg_flags);
+  if (msghdr->msg_flags & MSG_EOR)
+    printf (" MSG_EOR");
+  if (msghdr->msg_flags & MSG_TRUNC)
+    printf (" MSG_TRUNC");
+  if (msghdr->msg_flags & MSG_CTRUNC)
+    printf (" MSG_CTRUNC");
+  if (msghdr->msg_flags & MSG_OOB)
+    printf (" MSG_OOB");
+  if (msghdr->msg_flags & MSG_ERRQUEUE)
+    printf (" MSG_ERRQUEUE");
+
+  printf ("\n");
+}
+
+#endif /* defined(NETLINK_DEBUG) */
diff -Nur net-snmp-5.2.3.rr1/agent/mibgroup/disman/rtnetlinkTrigger.h net-snmp-5.2.3.rr1.new/agent/mibgroup/disman/rtnetlinkTrigger.h
--- net-snmp-5.2.3.rr1/agent/mibgroup/disman/rtnetlinkTrigger.h	1969-12-31 19:00:00.000000000 -0500
+++ net-snmp-5.2.3.rr1.new/agent/mibgroup/disman/rtnetlinkTrigger.h	2007-05-16 10:50:43.000000000 -0400
@@ -0,0 +1,53 @@
+/*
+ * snmpd_rtnetlink.h
+ */
+/*
+ * snmpd_rtnetlink.h provides support for the linux NETLINK mechanism
+ * for immediate triggering upon network interface link status change
+ */
+/*
+ * Copyright Ruggedcom, 2007 - Michael Leslie
+ */
+
+#ifndef _RTNETLINK_TRIGGER_H
+#define _RTNETLINK_TRIGGER_H
+
+#if defined(RTNETLINK_DECLS)
+#  define RTN_EXTERN
+#else
+#  define RTN_EXTERN extern
+#endif
+
+/**** Local definitions: ****************************************************/
+
+/* #define NETLINK_DEBUG */
+
+
+typedef void (rtnetlinkCallback)(unsigned int clientreg,
+				 void        *clientarg);
+
+struct rtnetlink_trigger
+{
+  void                     *clientarg;
+  rtnetlinkCallback        *callback;
+  unsigned int              clientreg;
+  struct rtnetlink_trigger *next;
+};
+
+/**** Variable declarations: ************************************************/
+
+RTN_EXTERN  int rtnetlink_fd; /* file descriptor of netlink socket */
+
+
+/**** Function prototypes: **************************************************/
+
+RTN_EXTERN void         init_rtnetlinkTrigger(void);
+RTN_EXTERN unsigned int netlink_trigger_register (rtnetlinkCallback *callback,
+					      void *clientarg);
+RTN_EXTERN unsigned int netlink_trigger_register_before (rtnetlinkCallback *callback,
+					      void *clientarg);
+RTN_EXTERN int          read_netlink_message (int fd);
+RTN_EXTERN void         run_netlink_triggers(int fd);
+
+#undef RTN_EXTERN
+#endif /* defined(_RTNETLINK_TRIGGER_H) */
diff -Nur net-snmp-5.2.3.rr1/agent/mibgroup/if-mib/ifTable/ifTable_interface.c net-snmp-5.2.3.rr1.new/agent/mibgroup/if-mib/ifTable/ifTable_interface.c
--- net-snmp-5.2.3.rr1/agent/mibgroup/if-mib/ifTable/ifTable_interface.c	2006-06-23 08:41:04.000000000 -0400
+++ net-snmp-5.2.3.rr1.new/agent/mibgroup/if-mib/ifTable/ifTable_interface.c	2007-05-16 10:50:54.000000000 -0400
@@ -279,6 +279,9 @@
      * inject cache helper
      */
     if (NULL != ifTable_if_ctx.cache) {
+#if HAVE_LINUX_RTNETLINK_H
+        ifTable_if_ctx.cache->flags |= NETSNMP_CACHE_NETLINK_TRIGGER;
+#endif
         handler = netsnmp_cache_handler_get(ifTable_if_ctx.cache);
         netsnmp_inject_handler(reginfo, handler);
     }
diff -Nur net-snmp-5.2.3.rr1/agent/snmpd.c net-snmp-5.2.3.rr1.new/agent/snmpd.c
--- net-snmp-5.2.3.rr1/agent/snmpd.c	2005-12-06 12:07:25.000000000 -0500
+++ net-snmp-5.2.3.rr1.new/agent/snmpd.c	2007-05-16 10:49:23.000000000 -0400
@@ -116,6 +116,10 @@
 #if HAVE_GRP_H
 #include <grp.h>
 #endif
+#if HAVE_LINUX_RTNETLINK_H
+#include <mibgroup/disman/rtnetlinkTrigger.h>
+#define USING_RTNETLINK
+#endif
 
 #ifndef PATH_MAX
 # ifdef _POSIX_PATH_MAX
@@ -1113,6 +1117,13 @@
         }
 #endif                          /* USING_SMUX_MODULE */
 
+#ifdef	USING_RTNETLINK
+	/* Add any rtnetlink fds to readfds. */
+	if (rtnetlink_fd)
+	  FD_SET(rtnetlink_fd, &readfds);
+
+#endif /* USING_RTNETLINK */
+
         for (i = 0; i < external_readfdlen; i++) {
             FD_SET(external_readfd[i], &readfds);
             if (external_readfd[i] >= numfds)
@@ -1139,6 +1150,17 @@
 
         if (count > 0) {
 
+#ifdef	USING_RTNETLINK
+	/* Handle any rtnetlink fds. */
+	  if (rtnetlink_fd) {
+	    if (FD_ISSET(rtnetlink_fd, &readfds)) {
+	      /* read_netlink_message (rtnetlink_fd);  */
+	      run_netlink_triggers (rtnetlink_fd);
+	    }
+	    
+	  }
+#endif /* USING_RTNETLINK */
+
 #ifdef USING_SMUX_MODULE
             /*
              * handle the SMUX sd's 
diff -Nur net-snmp-5.2.3.rr1/configure.in net-snmp-5.2.3.rr1.new/configure.in
--- net-snmp-5.2.3.rr1/configure.in	2007-05-16 10:40:29.000000000 -0400
+++ net-snmp-5.2.3.rr1.new/configure.in	2007-05-16 10:48:35.000000000 -0400
@@ -2528,6 +2528,21 @@
 ]])
 # Linux
 AC_CHECK_HEADERS(sys/conf.h netinet/tcp_fsm.h sys/protosw.h nlist.h ioctls.h asm/page.h asm/types.h netipx/ipx.h pci/pci.h)
+AC_CHECK_HEADERS(linux/netlink.h,,,
+[[
+#if HAVE_SOCKET_H
+#include <sys/socket.h>
+#endif
+]])
+AC_CHECK_HEADERS(linux/rtnetlink.h,,,
+[[
+#if HAVE_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_LINUX_NETLINK_H
+#include <linux/netlink.h>
+#endif
+]])
 # Solaris
 AC_CHECK_HEADERS(inet/mib2.h)
 # NetBSD required headers
diff -Nur net-snmp-5.2.3.rr1/include/net-snmp/agent/cache_handler.h net-snmp-5.2.3.rr1.new/include/net-snmp/agent/cache_handler.h
--- net-snmp-5.2.3.rr1/include/net-snmp/agent/cache_handler.h	2005-06-13 17:25:56.000000000 -0400
+++ net-snmp-5.2.3.rr1.new/include/net-snmp/agent/cache_handler.h	2007-05-16 10:48:59.000000000 -0400
@@ -103,6 +103,7 @@
 #define NETSNMP_CACHE_DONT_AUTO_RELEASE                     0x0008
 #define NETSNMP_CACHE_PRELOAD                               0x0010
 #define NETSNMP_CACHE_AUTO_RELOAD                           0x0020
+#define NETSNMP_CACHE_NETLINK_TRIGGER                       0x0040
 
 #define NETSNMP_CACHE_HINT_HANDLER_ARGS                     0x1000
 
diff -Nur net-snmp-5.2.3.rr1/include/net-snmp/net-snmp-config.h.in net-snmp-5.2.3.rr1.new/include/net-snmp/net-snmp-config.h.in
--- net-snmp-5.2.3.rr1/include/net-snmp/net-snmp-config.h.in	2006-05-26 12:37:06.000000000 -0400
+++ net-snmp-5.2.3.rr1.new/include/net-snmp/net-snmp-config.h.in	2007-05-16 10:49:08.000000000 -0400
@@ -384,6 +384,12 @@
 /* Define to 1 if you have the <linux/hdreg.h> header file. */
 #undef HAVE_LINUX_HDREG_H
 
+/* Define to 1 if you have the <linux/netlink.h> header file. */
+#undef HAVE_LINUX_NETLINK_H
+
+/* Define to 1 if you have the <linux/rtnetlink.h> header file. */
+#undef HAVE_LINUX_RTNETLINK_H
+
 /* Define to 1 if you have the <linux/tasks.h> header file. */
 #undef HAVE_LINUX_TASKS_H
 

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Net-snmp-coders mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders

Reply via email to