Index: usr.sbin/bsnmpd/modules/snmp_carp/snmp_carp.3 =================================================================== --- usr.sbin/bsnmpd/modules/snmp_carp/snmp_carp.3 (revision 0) +++ usr.sbin/bsnmpd/modules/snmp_carp/snmp_carp.3 (working copy) @@ -0,0 +1,139 @@ +.\"- +.\" Copyright (C) 2012 Shteryana Shopova +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd December 04, 2012 +.Dt SNMP_CARP 3 +.Os +.Sh NAME +.Nm snmp_carp +.Nd "CARP interfaces module for" +.Xr bsnmpd 1 +.Sh LIBRARY +.Pq begemotSnmpdModulePath."carp" = "/usr/lib/snmp_carp.so" +.Sh DESCRIPTION +The +.Nm snmp_carp +module implements the Begemot MIB for managing Common Address Redundancy Protocol +(CARP) interfaces. +.Sh IMPLEMENTATION NOTES +A short description of the objects implemented in the module follows. +.Bl -tag -width "XXXXXXXXX" +.It Va carpNotifications +Subtree containing notifications suported by +.Nm . +.Bl -tag -width ".It Va carpStatusChange" +.It Va carpStatusChange +This notification is when CARP status change event is detected. The Notification +contains the interface index of the interface, where the event occured, the +virtual host ID and its new state. +.El +.It Va carpSysctl +A subtree containing system-wide CARP control objects. The subtree contains the +following objects +.Bl -tag -width ".It Va carpAllow" +.It Va carpAllow +Specifies whether the system will accept CARP packets. +.It Va carpPreempt +Specifies whether virtual hosts will preempt each other. +.It Va carpLog +Specifies the current log level for +.Nm carp +events/packets. +.It Va carpDemotion +Specifies the current level of +.Nm carp +demotion. +.It Va carpSendErrDemotion +Specifies the value added to +.Nm carp + demotion when +.Nm carp +experiences errors sending its announcements. +.It Va carpIfDownDemotion +Specifies the value added to +.Nm carp + demotion when an interface running a virtual host goes down. +.El +.It Va carpIfTable +The table contains entries corresponding to each virtual host configured on +multicast-capable interfaces. An entry in the table contains the following +columns +.Bl -tag -width ".It Va carpIfIndex" +.It Va carpIfIndex +The interface index of the interface running the virtual host, entry index. +.It Va carpIfVhid +The ID of the virtual host, entry index. +.It Va carpIfDescr +The name of the interface running the virtual host. +.It Va carpIfAdvbase +The value of the advertisement base parameter for the virtual host. +.It Va carpIfAdvskew +The value of the advertisement skew parameter for the virtual host. +.It Va carpIfState +The current state of the virtual host, one of init(0), backup(1) or master(2). +.El +.It Va carpStats +The subtree contains various counters related to system-wide +.Nm carp +operation. +.El +.Sh FILES +.Bl -tag -width "XXXXXXXXX" +.It Pa /usr/share/snmp/mibs/BEGEMOT-CARP-MIB.txt +This is the BEGEMOT-CARP-MIB that is implemented by this module. It is based on +the original OPENBSD-CARP-MIB from OpenBSD, adapted to fit the implementation +changes of +.Nm carp(4) +interfaces in +.Nm FreeBSD 10. +.It Pa /usr/share/snmp/defs/carp_tree.def +The description of the MIB tree implemented by +.Nm +.El +.Sh SEE ALSO +.Xr bsnmpd 1 , +.Xr gensnmptree 1 , +.Xr snmpmod 3 , +.Xr carp 4 +.Sh AUTHORS +.An Shteryana Shopova Aq syrinx@FreeBSD.org +.Sh BUGS +The module has the following limitations : +.Pp +.Nm carpStatusChange +notification is currently not supported. +.Pp +.Nm +will flush and reread the whole module data from the kernel after every 15 +minutes of inactivity. +.Pp +.Nm +will search linearly for maching entries on SNMP GET/ GETNEXT requests. +.Pp +All data +.Nm +curently supports is read-only. Index: usr.sbin/bsnmpd/modules/snmp_carp/BEGEMOT-CARP-MIB.txt =================================================================== --- usr.sbin/bsnmpd/modules/snmp_carp/BEGEMOT-CARP-MIB.txt (revision 0) +++ usr.sbin/bsnmpd/modules/snmp_carp/BEGEMOT-CARP-MIB.txt (working copy) @@ -0,0 +1,370 @@ +-- +-- $OpenBSD: OPENBSD-CARP-MIB.txt,v 1.3 2012/09/28 09:21:48 jj Exp $ +-- +-- Copyright (c) 2006-2011 Joel Knight +-- +-- Copyright (C) 2012 Shteryana Shopova +-- All rights reserved. +-- +-- Permission to use, copy, modify, and distribute this document for any +-- purpose with or without fee is hereby granted, provided that the above +-- copyright notice and this permission notice appear in all copies. +-- +-- THE DOCUMENT IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +-- WITH REGARD TO THIS DOCUMENT INCLUDING ALL IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS DOCUMENT. +-- +-- $FreeBSD$ + +BEGEMOT-CARP-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, + Counter32, Integer32, TimeTicks, Unsigned32, mib-2, + Counter64 + FROM SNMPv2-SMI + TEXTUAL-CONVENTION, MacAddress, TruthValue, RowStatus, + DisplayString + FROM SNMPv2-TC + InterfaceIndex, ifIndex FROM IF-MIB + begemot + FROM BEGEMOT-MIB; + +begemotCarp MODULE-IDENTITY + LAST-UPDATED "201212040000Z" + ORGANIZATION "Sofia University St. Kliment Ohridski" + CONTACT-INFO + " Shteryana Shopova + + Postal: 12 Andrey Lyapchev Blvd. + block 2, ap.19 + 1797 Sofia + Bulgaria + + Fax: N/A + + E-Mail: syrinx@FreeBSD.org" + DESCRIPTION + "The Begemot MIB for managing Common Address Redundancy Protocol + (CARP) interfaces." + REVISION "201212040000Z" + DESCRIPTION + "Initial revision." + + ::= { begemot 211 } + +-- ---------------------------------------------------------- -- +-- Textual conventions +-- ---------------------------------------------------------- -- + +-- ---------------------------------------------------------- -- +-- Subtrees in the Begemot CARP MIB +-- ---------------------------------------------------------- -- +begemotCarpObjects OBJECT IDENTIFIER ::= { begemotCarp 1 } + +carpNotifications OBJECT IDENTIFIER ::= { begemotCarpObjects 0 } + +carpSysctl OBJECT IDENTIFIER ::= { begemotCarpObjects 1 } + +carpIf OBJECT IDENTIFIER ::= { begemotCarpObjects 2 } + +carpStats OBJECT IDENTIFIER ::= { begemotCarpObjects 3 } + +-- ---------------------------------------------------------- -- + +-- ---------------------------------------------------------- -- +-- Notifications +-- ---------------------------------------------------------- -- +carpStatusChange NOTIFICATION-TYPE + OBJECTS { carpIfIndex, carpIfVhid, carpIfState } + STATUS current + DESCRIPTION + "A notification for carp status change events." + ::= { carpNotifications 1 } + +-- ---------------------------------------------------------- -- +-- System-wide CARP interfaces' sysctl values +-- ---------------------------------------------------------- -- +carpAllow OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only -- XXX: shteryana - read-write + STATUS current + DESCRIPTION + "Accept incoming CARP packets." + DEFVAL { true } + ::= { carpSysctl 1 } + +carpPreempt OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "High-priority backup preemption mode." + DEFVAL { false } + ::= { carpSysctl 2 } + +carpLog OBJECT-TYPE + SYNTAX Integer32 (1..255) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "CARP log level." + DEFVAL { 1 } + ::= { carpSysctl 3 } + +carpDemotion OBJECT-TYPE + SYNTAX Integer32 (1..255) + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Demotion factor (skew of advskew)." + ::= { carpSysctl 4 } + +carpSendErrDemotion OBJECT-TYPE + SYNTAX Integer32 (1..255) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Send error demotion factor adjustment." + DEFVAL { 240 } + ::= { carpSysctl 5 } + +carpIfDownDemotion OBJECT-TYPE + SYNTAX Integer32 (1..255) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Interface down demotion factor adjustment." + DEFVAL { 240 } + ::= { carpSysctl 6 } + +-- ---------------------------------------------------------- -- +-- CARP interfaces' database +-- ---------------------------------------------------------- -- +carpIfTable OBJECT-TYPE + SYNTAX SEQUENCE OF CarpIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of individual CARP interfaces. The number of entries is + given by the value of carpIfNumber." + ::= { carpIf 1 } + +carpIfEntry OBJECT-TYPE + SYNTAX CarpIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry containing management information applicable to a + particular CARP interface." + INDEX { carpIfIndex, carpIfVhid } + ::= { carpIfTable 1 } + +CarpIfEntry ::= + SEQUENCE { + carpIfIndex Integer32, + carpIfVhid Integer32, + carpIfDescr OCTET STRING, + carpIfAdvbase Integer32, + carpIfAdvskew Integer32, + carpIfState Integer32 + } + +carpIfIndex OBJECT-TYPE + SYNTAX Integer32 (1..2147483647) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The ifIndex for the corresponding CARP interface." + ::= { carpIfEntry 1 } + +carpIfVhid OBJECT-TYPE + SYNTAX Integer32 (1..255) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Virtual HostID of the corresponding CARP interface." + ::= { carpIfEntry 2 } + +carpIfDescr OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the corresponding CARP interface." + ::= { carpIfEntry 3 } + + +carpIfAdvbase OBJECT-TYPE + SYNTAX Integer32 + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The advbase value of the CARP interface." + ::= { carpIfEntry 4 } + +carpIfAdvskew OBJECT-TYPE + SYNTAX Integer32 + UNITS " 1/256 seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The advskew value of the CARP interface." + ::= { carpIfEntry 5 } + +carpIfState OBJECT-TYPE + SYNTAX INTEGER { init(0), backup(1), master(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates the operational state of the CARP interface." + ::= { carpIfEntry 6 } + +-- ---------------------------------------------------------- -- +-- CARP statistics +-- ---------------------------------------------------------- -- + +carpIpPktsRecv OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv4 CARP packets received on all interfaces." + ::= { carpStats 1 } + +carpIp6PktsRecv OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv6 CARP packets received on all interfaces." + ::= { carpStats 2 } + +carpPktDiscardsForBadInterface OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packets discarded due to being received on a + non-CARP interface." + ::= { carpStats 3 } + +carpPktDiscardsForWrongTtl OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packets discarded due to having a TTL less + than 255." + ::= { carpStats 4 } + +carpPktShorterThanHeader OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packets received on any interface that is + shorter than the size of the CARP packet header." + ::= { carpStats 5 } + +carpPktDiscardsForBadChecksum OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packets discarded due to bad checksum." + ::= { carpStats 6 } + +carpPktDiscardsForBadVersion OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packets discarded due to bad version in + the packet header." + ::= { carpStats 7 } + +carpPktDiscardsForTooShort OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packets discarded due to being too short." + ::= { carpStats 8 } + +carpPktDiscardsForBadAuth OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packets discarded because they failed the + HMAC authentication check." + ::= { carpStats 9 } + +carpPktDiscardsForBadVhid OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packets discarded due to incorrect VHID in + the packet header." + ::= { carpStats 10 } + +carpPktDiscardsForBadAddressList OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packets discarded due to bad addresses in + the CARP packet." + ::= { carpStats 11 } + +carpIpPktsSent OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv4 CARP packets sent on all interfaces." + ::= { carpStats 12 } + +carpIp6PktsSent OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of IPv6 CARP packets sent on all interfaces." + ::= { carpStats 13 } + +carpNoMemory OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of CARP advertisements that failed because memory + could not be allocated." + ::= { carpStats 14 } + +carpStateUpdatesSent OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of CARP total state updates sent ." + ::= { carpStats 15 } + +carpTransitionsToMaster OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times the host has transitioned to MASTER state + for any CARP group." + ::= { carpStats 16 } + +END Index: usr.sbin/bsnmpd/modules/snmp_carp/carp_tree.def =================================================================== --- usr.sbin/bsnmpd/modules/snmp_carp/carp_tree.def (revision 0) +++ usr.sbin/bsnmpd/modules/snmp_carp/carp_tree.def (working copy) @@ -0,0 +1,83 @@ +#- +# Copyright (C) 2012 Shteryana Sotirova Shopova +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +(1 internet + (4 private + (1 enterprises + (12325 fokus + (1 begemot + (211 begemotCarp + (1 begemotCarpObjects + (0 carpNotifications + (1 carpStatusChange OID op_carp_status_change) + ) + (1 carpSysctl + (1 carpAllow ENUM ( 1 true 2 false ) op_carp_sysctl GET) + (2 carpPreempt ENUM ( 1 true 2 false ) op_carp_sysctl GET) + (3 carpLog INTEGER32 op_carp_sysctl GET) + (4 carpDemotion INTEGER32 op_carp_sysctl GET) + (5 carpSendErrDemotion INTEGER32 op_carp_sysctl GET) + (6 carpIfDownDemotion INTEGER32 op_carp_sysctl GET) + ) + (2 carpIf + (1 carpIfTable + (1 carpIfEntry : INTEGER INTEGER op_carp_if + (1 carpIfIndex INTEGER GET) + (2 carpIfVhid INTEGER GET) + (3 carpIfDescr OCTETSTRING | OctetString GET) + (4 carpIfAdvbase INTEGER32 GET) + (5 carpIfAdvskew INTEGER32 GET) + (6 carpIfState ENUM ( 0 init 1 backup 2 master ) GET) + ) + ) + ) + (3 carpStats + (1 carpIpPktsRecv COUNTER64 op_carp_stats GET) + (2 carpIp6PktsRecv COUNTER64 op_carp_stats GET) + (3 carpPktDiscardsForBadInterface COUNTER64 op_carp_stats GET) + (4 carpPktDiscardsForWrongTtl COUNTER64 op_carp_stats GET) + (5 carpPktShorterThanHeader COUNTER64 op_carp_stats GET) + (6 carpPktDiscardsForBadChecksum COUNTER64 op_carp_stats GET) + (7 carpPktDiscardsForBadVersion COUNTER64 op_carp_stats GET) + (8 carpPktDiscardsForTooShort COUNTER64 op_carp_stats GET) + (9 carpPktDiscardsForBadAuth COUNTER64 op_carp_stats GET) + (10 carpPktDiscardsForBadVhid COUNTER64 op_carp_stats GET) + (11 carpPktDiscardsForBadAddressList COUNTER64 op_carp_stats GET) + (12 carpIpPktsSent COUNTER64 op_carp_stats GET) + (13 carpIp6PktsSent COUNTER64 op_carp_stats GET) + (14 carpNoMemory COUNTER64 op_carp_stats GET) + (15 carpStateUpdatesSent COUNTER64 op_carp_stats GET) + (16 carpTransitionsToMaster COUNTER64 op_carp_stats GET) + ) + ) + ) + ) + ) + ) + ) +) Index: usr.sbin/bsnmpd/modules/snmp_carp/carp_snmp.c =================================================================== --- usr.sbin/bsnmpd/modules/snmp_carp/carp_snmp.c (revision 0) +++ usr.sbin/bsnmpd/modules/snmp_carp/carp_snmp.c (working copy) @@ -0,0 +1,630 @@ +/*- + * Copyright (c) 2012 Shteryana Shopova + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "carp_tree.h" +#include "carp_oid.h" + +static struct lmodule *carp_module; + +static int started __unused; +static uint64_t carp_tick; +static int sock; + +#define CARP_DATA_MAXAGE 5 +/* By default poll kernel data every 15 minutes. */ +#define CARP_POLL_INTERVAL (15 * 60) + +static int carp_poll_ticks = CARP_POLL_INTERVAL * 100; +static void *carp_data_timer; + +struct carp_sysctl { + int32_t carp_allow; + int32_t carp_preempt; + int32_t carp_log; + int32_t carp_demotion; + int32_t senderr_demotion_factor; + int32_t ifdown_demotion_factor; +}; + +#define CARP_SYSCTLS (sizeof(struct carp_sysctl) / sizeof(int32_t)) + +struct carp_vhid { + uint8_t vhid; + uint8_t state; + uint8_t advskew; + uint8_t advbase; + struct carp_if *iface; + STAILQ_ENTRY(carp_vhid) link; +}; + + +struct carp_if { + char name[IFNAMSIZ]; + uint32_t index; + STAILQ_HEAD(vhid_list, carp_vhid) vhlist; + STAILQ_ENTRY(carp_if) link; +}; + +static struct { + struct carp_sysctl sysctls; + STAILQ_HEAD(carp_iflist, carp_if) iflist; + struct carpstats stats; +} carp_data; + +void carp_poll(void *); +static int carp_refresh(void); +static struct carp_sysctl *carp_get_sysctls(void); +static struct carp_iflist *carp_get_iflist(void); +static struct carpstats *carp_get_stats(void); +static struct carp_vhid *carp_vhid_first(void); +static struct carp_vhid *carp_vhid_find(uint32_t, uint8_t); +static struct carp_vhid *carp_vhid_next(struct carp_vhid *); +static int32_t carp_refresh_sysctls(struct carp_sysctl *); +static int32_t carp_refresh_iflist(struct carp_iflist *); +static int32_t carp_refresh_stats(struct carpstats *); + +/* For the registration. */ +static const struct asn_oid oid_begemotCarp = OIDX_begemotCarp; +/* The registration. */ +static uint reg_carp; + +int +op_carp_sysctl(struct snmp_context *ctx __unused, struct snmp_value *val, + uint32_t sub __unused, uint32_t iidx __unused, enum snmp_op op) +{ + struct carp_sysctl *ctls; + asn_subid_t which = val->var.subs[sub - 1]; + + if (op == SNMP_OP_SET) + return (SNMP_ERR_NOT_WRITEABLE); + + if (op == SNMP_OP_GET) { + if ((time(NULL) - carp_tick) > CARP_DATA_MAXAGE) + if (carp_refresh() == -1) + return (SNMP_ERR_GENERR); + ctls = carp_get_sysctls(); + + switch (which) { + case LEAF_carpAllow: + val->v.integer = ctls->carp_allow; + break; + case LEAF_carpPreempt: + val->v.integer = ctls->carp_preempt; + break; + case LEAF_carpLog: + val->v.integer = ctls->carp_log; + break; + case LEAF_carpDemotion: + val->v.integer = ctls->carp_demotion; + break; + case LEAF_carpSendErrDemotion: + val->v.integer = ctls->senderr_demotion_factor; + break; + case LEAF_carpIfDownDemotion: + val->v.integer = ctls->ifdown_demotion_factor; + break; + default: + return (SNMP_ERR_NOSUCHNAME); + } + return (SNMP_ERR_NOERROR); + } + + abort(); +} + +int +op_carp_if(struct snmp_context *ctx __unused, struct snmp_value *val, + uint32_t sub __unused, uint32_t iidx __unused, enum snmp_op op __unused) +{ + uint32_t ifindex; + uint8_t vhid; + asn_subid_t which = val->var.subs[sub - 1]; + struct carp_vhid *vh; + + if ((time(NULL) - carp_tick) > CARP_DATA_MAXAGE) + if (carp_refresh() == -1) + return (SNMP_ERR_GENERR); + + switch (op) { + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + case SNMP_OP_GETNEXT: + if (val->var.len - sub == 0) { + if ((vh = carp_vhid_first()) == NULL) + return (SNMP_ERR_NOSUCHNAME); + val->var.subs[sub] = vh->iface->index; + val->var.subs[sub + 1] = vh->vhid; + val->var.len += 2; + } else { + if (val->var.len - sub != 2) + return (SNMP_ERR_NOSUCHNAME); + ifindex = val->var.subs[sub]; + if (val->var.subs[sub + 1] > CARP_MAXVHID) + return (SNMP_ERR_WRONG_VALUE); + vhid = val->var.subs[sub + 1]; + if ((vh = carp_vhid_find(ifindex, vhid)) == NULL || + (vh = carp_vhid_next(vh)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + val->var.subs[sub] = vh->iface->index; + val->var.subs[sub + 1] = vh->vhid; + } + break; + case SNMP_OP_GET: + if (val->var.len - sub != 2) + return (SNMP_ERR_NOSUCHNAME); + ifindex = val->var.subs[sub]; + if (val->var.subs[sub + 1] > CARP_MAXVHID) + return (SNMP_ERR_WRONG_VALUE); + vhid = val->var.subs[sub + 1]; + if ((vh = carp_vhid_find(ifindex, vhid)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + case SNMP_OP_COMMIT: + case SNMP_OP_ROLLBACK: + default: + abort(); + } + + switch (which) { + case LEAF_carpIfIndex: + val->v.integer = vh->iface->index; + break; + case LEAF_carpIfVhid: + val->v.integer = vh->vhid; + break; + case LEAF_carpIfDescr: + return (string_get(val, vh->iface->name, -1)); + case LEAF_carpIfAdvbase: + val->v.integer = vh->advbase; + break; + case LEAF_carpIfAdvskew: + val->v.integer = vh->advskew; + break; + case LEAF_carpIfState: + val->v.integer = vh->state; + break; + default: + return (SNMP_ERR_NOSUCHNAME); + } + + return (SNMP_ERR_NOERROR); +} + +int +op_carp_stats(struct snmp_context *ctx __unused, struct snmp_value *val, + uint32_t sub __unused, uint32_t iidx __unused, enum snmp_op op __unused) +{ + struct carpstats *stats; + asn_subid_t which = val->var.subs[sub - 1]; + + if (op == SNMP_OP_SET) + return (SNMP_ERR_NOT_WRITEABLE); + + if (op == SNMP_OP_GET) { + if ((time(NULL) - carp_tick) > CARP_DATA_MAXAGE) + if (carp_refresh() == -1) + return (SNMP_ERR_GENERR); + stats = carp_get_stats(); + + switch (which) { + case LEAF_carpIpPktsRecv: + val->v.counter64 = stats->carps_ipackets; + break; + case LEAF_carpIp6PktsRecv: + val->v.counter64 = stats->carps_ipackets6; + break; + case LEAF_carpPktDiscardsForBadInterface: + val->v.counter64 = stats->carps_badif; + break; + case LEAF_carpPktDiscardsForWrongTtl: + val->v.counter64 = stats->carps_badttl; + break; + case LEAF_carpPktShorterThanHeader: + val->v.counter64 = stats->carps_hdrops; + break; + case LEAF_carpPktDiscardsForBadChecksum: + val->v.counter64 = stats->carps_badsum; + break; + case LEAF_carpPktDiscardsForBadVersion: + val->v.counter64 = stats->carps_badver; + break; + case LEAF_carpPktDiscardsForTooShort: + val->v.counter64 = stats->carps_badlen; + break; + case LEAF_carpPktDiscardsForBadAuth: + val->v.counter64 = stats->carps_badauth; + break; + case LEAF_carpPktDiscardsForBadVhid: + val->v.counter64 = stats->carps_badvhid; + break; + case LEAF_carpPktDiscardsForBadAddressList: + val->v.counter64 = stats->carps_badaddrs; + break; + case LEAF_carpIpPktsSent: + val->v.counter64 = stats->carps_opackets; + break; + case LEAF_carpIp6PktsSent: + val->v.counter64 = stats->carps_opackets6; + break; + case LEAF_carpNoMemory: + val->v.counter64 = stats->carps_onomem; + break; + case LEAF_carpStateUpdatesSent: + val->v.counter64 = stats->carps_ostates; + break; + case LEAF_carpTransitionsToMaster: + val->v.counter64 = stats->carps_preempt; + break; + default : + return (SNMP_ERR_NOSUCHNAME); + } + return (SNMP_ERR_NOERROR); + } + + abort(); +} + +void +carp_poll(void *arg __unused) +{ + (void)carp_refresh(); +} + +static int +carp_refresh(void) +{ + if (carp_refresh_sysctls(carp_get_sysctls()) < 0) + return (-1); + if (carp_refresh_iflist(carp_get_iflist()) < 0) + return (-1); + if (carp_refresh_stats(carp_get_stats()) < 0) + return (-1); + + carp_tick = this_tick; + + return (0); +} + +const char carp_sysctl_name[] = "net.inet.carp."; + +static const char *carp_sysctl[] = { + "allow", + "preempt", + "log", + "demotion", + "senderr_demotion_factor", + "ifdown_demotion_factor", + "stats" +}; + +static int32_t +carp_refresh_sysctls(struct carp_sysctl *s) +{ + char mib_name[100]; + int32_t values[CARP_SYSCTLS]; + uint32_t i; + size_t len; + + strlcpy(mib_name, carp_sysctl_name, sizeof(mib_name)); + + for (i = 0, len = sizeof(int32_t); i < CARP_SYSCTLS; i++) { + mib_name[strlen(carp_sysctl_name)] = '\0'; + strlcat(mib_name, carp_sysctl[i], sizeof(mib_name)); + + if (sysctlbyname(mib_name, (values + i), &len, NULL, 0) < 0) { + syslog(LOG_ERR, "sysctl(%s) failed - %s", mib_name, + strerror(errno)); + return (-1); + } + } + + /* XXX: ugly */ + s->carp_allow = values[LEAF_carpAllow - 1]; + s->carp_preempt = values[LEAF_carpPreempt - 1]; + s->carp_log = values[LEAF_carpLog - 1]; + s->carp_demotion = values[LEAF_carpDemotion - 1]; + s->senderr_demotion_factor = values[LEAF_carpSendErrDemotion - 1]; + s->ifdown_demotion_factor = values[LEAF_carpIfDownDemotion - 1]; + + return (0); +} + +static int32_t +carp_refresh_iflist(struct carp_iflist *iflist) +{ + int32_t i; + struct carp_if *iface; + struct carp_vhid *vh; + struct mibif *mif; + struct ifreq ifr; + struct carpreq carpr[CARP_MAXVHID]; + + /* XXX: FIXME - shteryana !!! */ + while ((iface = STAILQ_FIRST(iflist)) != NULL) { + STAILQ_REMOVE_HEAD(iflist, link); + while ((vh = STAILQ_FIRST(&iface->vhlist)) != NULL) { + STAILQ_REMOVE_HEAD(&iface->vhlist, link); + free(vh); + } + free(iface); + } + STAILQ_INIT(iflist); + + for (mif = mib_first_if(); mif != NULL; mif = mib_next_if(mif)) { + if (mif->mib.ifmd_data.ifi_type != IFT_ETHER && + mif->mib.ifmd_data.ifi_type != IFT_BRIDGE && + mif->mib.ifmd_data.ifi_type != IFT_L2VLAN && + mif->mib.ifmd_data.ifi_type != IFT_FDDI && + mif->mib.ifmd_data.ifi_type != IFT_ISO88025) + continue; + if ((iface = (struct carp_if *)malloc(sizeof(*iface))) == NULL) { + syslog(LOG_ERR, "carp new interface failed: %s", + strerror(errno)); + return (-1); + } + memset(iface, 0, sizeof(*iface)); + strlcpy(iface->name, mif->name, IFNAMSIZ); + iface->index = mif->index; + STAILQ_INIT(&iface->vhlist); + STAILQ_INSERT_TAIL(iflist, iface, link); + + memset(&ifr, 0, sizeof(ifr)); + memset(carpr, 0, CARP_MAXVHID * sizeof(struct carpreq)); + carpr[0].carpr_count = CARP_MAXVHID; + strcpy(ifr.ifr_name, iface->name); + ifr.ifr_data = (caddr_t)&carpr; + + if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1) { + if (errno != ENOENT) { + syslog(LOG_ERR, "ioctl(SIOCGVH) failed: %s", + strerror(errno)); + return (-1); + } + continue; + } + + /* XXX: hope that kernel returns sorted results */ + for (i = 0; i < carpr[0].carpr_count; i++) { + if ((vh = (struct carp_vhid *)malloc(sizeof(*vh))) + == NULL) { + syslog(LOG_ERR, "carp new interface failed: %s", + strerror(errno)); + return (-1); + } + memset(vh, 0, sizeof(vh)); + vh->vhid = carpr[i].carpr_vhid; + vh->state = carpr[i].carpr_state; + vh->advskew = carpr[i].carpr_advskew; + vh->advbase = carpr[i].carpr_advbase; + vh->iface = iface; + STAILQ_INSERT_TAIL(&iface->vhlist, vh, link); + } + } + + return (0); +} + +static int32_t +carp_refresh_stats(struct carpstats *s) +{ + char mib_name[100]; + size_t len = sizeof(struct carpstats); + + strlcpy(mib_name, carp_sysctl_name, sizeof(mib_name)); + strlcat(mib_name, "stats", sizeof(mib_name)); + + if (sysctlbyname(mib_name, s, &len, NULL, 0) < 0 || + len != sizeof(struct carpstats)) { + syslog(LOG_ERR, "sysctl(%s) failed - %s", mib_name, + strerror(errno)); + return (-1); + } + + return (0); +} + +static struct carp_sysctl * +carp_get_sysctls(void) +{ + return (&carp_data.sysctls); +} + +static struct carp_iflist * +carp_get_iflist(void) +{ + return (&carp_data.iflist); +} + +static struct carpstats * +carp_get_stats(void) +{ + return (&carp_data.stats); +} + +static struct carp_vhid * +carp_vhid_first(void) +{ + struct carp_vhid *vh; + struct carp_if *iface; + struct carp_iflist *iflist = carp_get_iflist(); + + iface = STAILQ_FIRST(iflist); + while (iface != NULL && (vh = STAILQ_FIRST(&iface->vhlist)) == NULL) + iface = STAILQ_NEXT(iface, link); + + if (iface == NULL) + return (NULL); + + return (vh); +} + +static struct carp_vhid * +carp_vhid_find(uint32_t ifindex, uint8_t vhid) +{ + struct carp_vhid *vh; + struct carp_if *iface; + struct carp_iflist *iflist = carp_get_iflist(); + + STAILQ_FOREACH(iface, iflist, link) { + if (iface->index == ifindex) { + STAILQ_FOREACH(vh, &iface->vhlist, link) { + if (vh->vhid == vhid) + return (vh); + else if (vh->vhid > vhid) + return (NULL); + } + } else if (iface->index > ifindex) + return (NULL); + } + + return (NULL); +} + +static struct carp_vhid * +carp_vhid_next(struct carp_vhid *v) +{ + struct carp_vhid *vh; + struct carp_if *iface; + + if ((vh = STAILQ_NEXT(v, link)) == NULL) { + iface = v->iface; + do { + iface = STAILQ_NEXT(iface, link); + } while (iface != NULL && + (vh = STAILQ_FIRST(&iface->vhlist)) == NULL); + } + + return (vh); +} + +static int +carp_init(struct lmodule * mod, int argc __unused, char *argv[] __unused) +{ + carp_module = mod; + + /* kmod load */ + if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "cannot open socket : %s", strerror(errno)); + return (-1); + } + /* Register to get creation messages for additional interfaces.? */ + + return (0); +} + +static void +carp_start(void) +{ + reg_carp = or_register(&oid_begemotCarp, + "The Begemot MIB for managing CARP interfaces.", carp_module); + + carp_data_timer = timer_start_repeat(carp_poll_ticks, + carp_poll_ticks, carp_poll, NULL, carp_module); +} + +static int +carp_fini(void) +{ + or_unregister(reg_carp); + + if (carp_data_timer != NULL) { + timer_stop(carp_data_timer); + carp_data_timer = NULL; + } + + close(sock); + + return (0); +} + +static void +carp_dump(void) +{ + struct carp_sysctl *sctl = carp_get_sysctls(); + struct carpstats *sts = carp_get_stats(); + struct carp_vhid *vh; + + syslog(LOG_DEBUG, "allow %d, preempt %d, log %d, demotion %d, sender %d" + ", ifdown %d", sctl->carp_allow, sctl->carp_preempt, sctl->carp_log, + sctl->carp_demotion, sctl->senderr_demotion_factor, + sctl->ifdown_demotion_factor); + + for (vh = carp_vhid_first(); vh != NULL; vh = carp_vhid_next(vh)) + syslog(LOG_DEBUG, "ifindex %d, vhid %d, descr %s, state %d", + vh->iface->index, vh->vhid, vh->iface->name, vh->state); + + syslog(LOG_DEBUG, "ipackets %ju, ipackets6 %ju, badif %ju, badttl %ju", + sts->carps_ipackets, sts->carps_ipackets6, sts->carps_badif, + sts->carps_badttl); + syslog(LOG_DEBUG, "hdrops %ju, badsum %ju, badver %ju, badlen %ju", + sts->carps_hdrops, sts->carps_badsum, sts->carps_badver, + sts->carps_badlen); + syslog(LOG_DEBUG, "badauth %ju, badvhid %ju, badaddrs %ju, opackets %ju", + sts->carps_badauth, sts->carps_badvhid, sts->carps_badaddrs, + sts->carps_opackets); + syslog(LOG_DEBUG, "opackets6 %ju, onomem %ju, ostates %ju, preempt %ju", + sts->carps_opackets6, sts->carps_onomem, sts->carps_ostates, + sts->carps_preempt); + +} + +const char carp_comment[] = \ +"This module implements the Begemot MIB for managing CARP interfaces"; + +const struct snmp_module config = { + .comment = carp_comment, + .init = carp_init, + .fini = carp_fini, + .start = carp_start, + .tree = carp_ctree, + .dump = carp_dump, + .tree_size = carp_CTREE_SIZE, +}; Index: usr.sbin/bsnmpd/modules/snmp_carp/Makefile =================================================================== --- usr.sbin/bsnmpd/modules/snmp_carp/Makefile (revision 0) +++ usr.sbin/bsnmpd/modules/snmp_carp/Makefile (working copy) @@ -0,0 +1,18 @@ +# $FreeBSD$ +# +# Author: Shteryana Shopova + +MOD= carp +SRCS= carp_snmp.c carp_sys.c +CFLAGS+= -DSNMPTREE_TYPES + +#XXX: remove +CFLAGS+= -g -Wall -Werror + +XSYM= begemotCarp carpStatusChange + +MAN= snmp_${MOD}.3 +DEFS= ${MOD}_tree.def +BMIBS= BEGEMOT-CARP-MIB.txt + +.include