hi,

the following diff adds the linkUp/Down traps to snmpd.  this will
help to track interface link state changes via snmp and also virtual
link states like carp(4) BACKUP <-> MASTER transitions.  snmpd(8)
monitors the link state changes and send traps to the configured
receivers accordingly.

limitations:
- the traps are SNMPv2-only.  some NMS seem to stick on v1 linkUp/Down.
- the ifLinkUpDownTrapEnable is always enabled for every interface and
is not considering stacking (eg. a trap will be send for every vlan if
parent goes down).

comments?

reyk

Index: kroute.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/kroute.c,v
retrieving revision 1.15
diff -u -p -r1.15 kroute.c
--- kroute.c    15 Oct 2010 09:27:03 -0000      1.15
+++ kroute.c    16 Mar 2011 16:05:05 -0000
@@ -623,9 +623,16 @@ kif_update(u_short if_index, int flags, 
        struct ether_addr       *ea;
        struct ifreq             ifr;
 
-       if ((kif = kif_find(if_index)) == NULL)
+       if ((kif = kif_find(if_index)) == NULL) {
                if ((kif = kif_insert(if_index)) == NULL)
                        return (NULL);
+       } else {
+               if (((flags & (IFF_UP)) &&
+                   LINK_STATE_IS_UP(ifd->ifi_link_state)) !=
+                   ((kif->k.if_flags & (IFF_UP)) &&
+                   LINK_STATE_IS_UP(kif->k.if_link_state)))
+                       trap_link(if_index, flags, ifd->ifi_link_state);
+       }
 
        kif->k.if_flags = flags;
        bcopy(ifd, &kif->k.if_data, sizeof(struct if_data));
Index: mib.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/mib.c,v
retrieving revision 1.43
diff -u -p -r1.43 mib.c
--- mib.c       15 Oct 2010 11:56:13 -0000      1.43
+++ mib.c       16 Mar 2011 16:05:06 -0000
@@ -953,19 +953,12 @@ mib_iftable(struct oid *oid, struct ber_
                break;
        case 7:
                /* ifAdminStatus up(1), down(2), testing(3) */
-               i = (kif->if_flags & IFF_UP) ? 1 : 2;
+               i = smi_ifadminstatus(kif->if_flags);
                ber = ber_add_integer(ber, i);
                break;
        case 8:
                /* ifOperStatus */
-               if ((kif->if_flags & IFF_UP) == 0) {
-                       i = 2;  /* down(2) */
-               } else if (LINK_STATE_IS_UP(kif->if_link_state)) {
-                       i = 1;  /* up(1) */
-               } else if (kif->if_link_state == LINK_STATE_DOWN) {
-                       i = 7;  /* lowerLayerDown(7) or dormant(5)? */
-               } else
-                       i = 4;  /* unknown(4) */
+               i = smi_ifoperstatus(kif->if_flags, kif->if_link_state);
                ber = ber_add_integer(ber, i);
                break;
        case 9:
@@ -1116,7 +1109,7 @@ mib_ifxtable(struct oid *oid, struct ber
                ber_set_header(ber, BER_CLASS_APPLICATION, SNMP_T_COUNTER64);
                break;
        case 14:
-               ber = ber_add_integer(ber, 0);  /* enabled(1), disabled(2) */
+               ber = ber_add_integer(ber, 1);  /* enabled(1), disabled(2) */
                break;
        case 15:
                i = kif->if_baudrate >= 1000000 ?
Index: smi.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/smi.c,v
retrieving revision 1.6
diff -u -p -r1.6 smi.c
--- smi.c       16 Dec 2009 22:17:53 -0000      1.6
+++ smi.c       16 Mar 2011 16:05:06 -0000
@@ -69,6 +69,27 @@ smi_getticks(void)
        return (ticks);
 }
 
+int
+smi_ifadminstatus(int flags)
+{
+       /* ifAdminStatus up(1), down(2), testing(3) */
+       return ((flags & IFF_UP) ? 1 : 2);
+}
+
+int
+smi_ifoperstatus(int flags, u_int8_t link_state)
+{
+       if ((flags & IFF_UP) == 0)
+               return (2);     /* down(2) */
+       else if (LINK_STATE_IS_UP(link_state))
+               return (1);     /* up(1) */
+       else if (link_state == LINK_STATE_DOWN)
+               return (7);     /* lowerLayerDown(7) or dormant(5)? */
+       else
+               return (4);     /* unknown(4) */
+       /* NOTREACHED */
+}
+
 void
 smi_oidlen(struct ber_oid *o)
 {
Index: snmpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/snmpd.h,v
retrieving revision 1.30
diff -u -p -r1.30 snmpd.h
--- snmpd.h     20 Sep 2010 08:56:16 -0000      1.30
+++ snmpd.h     16 Mar 2011 16:05:06 -0000
@@ -359,6 +359,7 @@ void                 snmpe_debug_elements(struct ber_e
 void            trap_init(void);
 int             trap_imsg(struct imsgev *, pid_t);
 int             trap_send(struct ber_oid *, struct ber_element *);
+void            trap_link(u_short, int, u_int8_t);
 
 /* mps.c */
 struct ber_element *
@@ -393,6 +394,8 @@ char                *smi_oidstring(struct ber_oid *, c
 void            smi_delete(struct oid *);
 void            smi_insert(struct oid *);
 int             smi_oid_cmp(struct oid *, struct oid *);
+int             smi_ifadminstatus(int);
+int             smi_ifoperstatus(int, u_int8_t);
 
 /* timer.c */
 void            timer_init(void);
Index: trap.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/trap.c,v
retrieving revision 1.15
diff -u -p -r1.15 trap.c
--- trap.c      16 Mar 2011 15:30:35 -0000      1.15
+++ trap.c      16 Mar 2011 16:05:06 -0000
@@ -195,6 +195,44 @@ trap_imsg(struct imsgev *iev, pid_t pid)
        return (ret);
 }
 
+void
+trap_link(u_short if_index, int flags, u_int8_t link_state)
+{
+       struct ber_oid           linkup = OID(MIB_linkUp);
+       struct ber_oid           linkdown = OID(MIB_linkDown);
+       struct ber_oid           ifindex = OID(MIB_ifIndex);
+       struct ber_oid           ifadmin = OID(MIB_ifAdminStatus);
+       struct ber_oid           ifoper = OID(MIB_ifOperStatus);
+       int                      idx, admin, oper;
+       struct ber_element      *ber;
+
+       smi_oidlen(&ifindex);
+       ifindex.bo_id[ifindex.bo_n++] = if_index;
+       idx = if_index;
+
+       smi_oidlen(&ifadmin);
+       ifadmin.bo_id[ifadmin.bo_n++] = if_index;
+       admin = smi_ifadminstatus(flags);
+
+       smi_oidlen(&ifoper);
+       ifoper.bo_id[ifoper.bo_n++] = if_index;
+       oper = smi_ifoperstatus(flags, link_state);
+
+       ber = ber_add_sequence(NULL);
+       if ((ber_printf_elements(ber, "Od}{Od}{Od}",
+           &ifindex, idx,
+           &ifadmin, admin,
+           &ifoper, oper)) == NULL) {
+               log_warnx("trap_link: failed to create trap");
+               return;
+       }
+
+       if ((flags & IFF_UP) && LINK_STATE_IS_UP(link_state))
+               trap_send(&linkup, ber);
+       else
+               trap_send(&linkdown, ber);
+}
+
 int
 trap_send(struct ber_oid *oid, struct ber_element *elm)
 {

Reply via email to