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) {