hostres_network_tbl.c revision 154133
121308Sache/*- 221308Sache * Copyright (c) 2005-2006 The FreeBSD Project 321308Sache * All rights reserved. 421308Sache * 521308Sache * Author: Victor Cruceru <soc-victor@freebsd.org> 621308Sache * 721308Sache * Redistribution of this software and documentation and use in source and 821308Sache * binary forms, with or without modification, are permitted provided that 921308Sache * the following conditions are met: 1058310Sache * 1121308Sache * 1. Redistributions of source code or documentation must retain the above 1221308Sache * copyright notice, this list of conditions and the following disclaimer. 1321308Sache * 2. Redistributions in binary form must reproduce the above copyright 1421308Sache * notice, this list of conditions and the following disclaimer in the 1521308Sache * documentation and/or other materials provided with the distribution. 1621308Sache * 1721308Sache * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1821308Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1921308Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2021308Sache * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2158310Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2221308Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2321308Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2421308Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2521308Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2621308Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2721308Sache * SUCH DAMAGE. 2826497Sache * 2926497Sache * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_network_tbl.c 154133 2006-01-09 12:33:45Z harti $ 3058310Sache */ 3158310Sache 3221308Sache/* 3321308Sache * Host Resources MIB implementation for SNMPd: instrumentation for 3421308Sache * hrNetworkTable 3521308Sache */ 3621308Sache 3721308Sache#include <sys/types.h> 3821308Sache#include <sys/ioctl.h> 3921308Sache#include <sys/socket.h> 4021308Sache#include <sys/sysctl.h> 4121308Sache 4221308Sache#include <net/if.h> 4321308Sache#include <net/if_mib.h> 4421308Sache 4521308Sache#include <assert.h> 4621308Sache#include <ctype.h> 4721308Sache#include <err.h> 4821308Sache#include <errno.h> 4958310Sache#include <ifaddrs.h> 5058310Sache#include <stdarg.h> 5158310Sache#include <stdlib.h> 5221308Sache#include <string.h> 5326497Sache#include <syslog.h> 5421308Sache#include <unistd.h> 5521308Sache 5621308Sache#include "hostres_snmp.h" 5721308Sache#include "hostres_oid.h" 5821308Sache#include "hostres_tree.h" 5921308Sache 6021308Sache#include <bsnmp/snmp_mibII.h> 6121308Sache 6221308Sache/* 6321308Sache * This structure is used to hold a SNMP table entry 6421308Sache * for HOST-RESOURCES-MIB's hrNetworkTable 6521308Sache */ 6621308Sachestruct network_entry { 6721308Sache int32_t index; 6821308Sache int32_t ifIndex; 6921308Sache TAILQ_ENTRY(network_entry) link; 7035486Sache#define HR_NETWORK_FOUND 0x001 7121308Sache uint32_t flags; 7221308Sache 7321308Sache}; 74119610SacheTAILQ_HEAD(network_tbl, network_entry); 75119610Sache 7626497Sache/* the head of the list with hrNetworkTable's entries */ 7721308Sachestatic struct network_tbl network_tbl = TAILQ_HEAD_INITIALIZER(network_tbl); 78136644Sache 79136644Sache/* last (agent) tick when hrNetworkTable was updated */ 80136644Sachestatic uint64_t network_tick; 81136644Sache 82136644Sache/* maximum number of ticks between updates of network table */ 83136644Sacheuint32_t network_tbl_refresh = HR_NETWORK_TBL_REFRESH * 100; 84136644Sache 85136644Sache/* Constants */ 86136644Sachestatic const struct asn_oid OIDX_hrDeviceNetwork_c = OIDX_hrDeviceNetwork; 87136644Sache 88136644Sache/** 89136644Sache * Create a new entry into the network table 90136644Sache */ 91136644Sachestatic struct network_entry * 92136644Sachenetwork_entry_create(const struct device_entry *devEntry) 93136644Sache{ 94136644Sache struct network_entry *entry; 9521308Sache 9621308Sache assert(devEntry != NULL); 9721308Sache if (devEntry == NULL) 9821308Sache return (NULL); 9921308Sache 10021308Sache if ((entry = malloc(sizeof(*entry))) == NULL) { 10126497Sache syslog(LOG_WARNING, "%s: %m", __func__); 10226497Sache return (NULL); 10326497Sache } 104136644Sache 10526497Sache memset(entry, 0, sizeof(*entry)); 10626497Sache entry->index = devEntry->index; 107136644Sache INSERT_OBJECT_INT(entry, &network_tbl); 108136644Sache 109136644Sache return (entry); 110136644Sache} 111136644Sache 112136644Sache/** 113136644Sache * Delete an entry in the network table 114136644Sache */ 115136644Sachestatic void 116136644Sachenetwork_entry_delete(struct network_entry* entry) 117136644Sache{ 118136644Sache 11926497Sache TAILQ_REMOVE(&network_tbl, entry, link); 12026497Sache free(entry); 12126497Sache} 12226497Sache 12326497Sache/** 12426497Sache * Fetch the interfaces from the mibII module, get their real name from the 12526497Sache * kernel and try to find it in the device table. 12626497Sache */ 12726497Sachestatic void 12826497Sachenetwork_get_interfaces(void) 12926497Sache{ 13021308Sache struct device_entry *dev; 13121308Sache struct network_entry *net; 13221308Sache struct mibif *ifp; 13326497Sache int name[6]; 13426497Sache size_t len; 13526497Sache char *dname; 136136644Sache 137136644Sache name[0] = CTL_NET; 13821308Sache name[1] = PF_LINK; 13921308Sache name[2] = NETLINK_GENERIC; 14021308Sache name[3] = IFMIB_IFDATA; 14121308Sache name[5] = IFDATA_DRIVERNAME; 14221308Sache 14321308Sache for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) { 14421308Sache HRDBG("%s %s", ifp->name, ifp->descr); 14521308Sache 14621308Sache name[4] = ifp->sysindex; 14721308Sache 14821308Sache /* get the original name */ 14921308Sache len = 0; 15026497Sache if (sysctl(name, 6, NULL, &len, 0, 0) < 0) { 15126497Sache syslog(LOG_ERR, "sysctl(net.link.ifdata.%d." 15221308Sache "drivername): %m", ifp->sysindex); 15321308Sache continue; 15426497Sache } 15521308Sache if ((dname = malloc(len)) == NULL) { 15621308Sache syslog(LOG_ERR, "malloc: %m"); 15721308Sache continue; 15821308Sache } 15921308Sache if (sysctl(name, 6, dname, &len, 0, 0) < 0) { 16021308Sache syslog(LOG_ERR, "sysctl(net.link.ifdata.%d." 16121308Sache "drivername): %m", ifp->sysindex); 16221308Sache free(dname); 16321308Sache continue; 16421308Sache } 16521308Sache 16621308Sache HRDBG("got device %s (%s)", ifp->name, dname); 16721308Sache 16821308Sache if ((dev = device_find_by_name(dname)) == NULL) { 16921308Sache HRDBG("%s not in hrDeviceTable", dname); 17021308Sache free(dname); 171119610Sache continue; 17221308Sache } 17321308Sache HRDBG("%s found in hrDeviceTable", dname); 174119610Sache 17521308Sache dev->type = OIDX_hrDeviceNetwork_c; 17621308Sache dev->flags |= HR_DEVICE_IMMUTABLE; 17721308Sache 17821308Sache free(dname); 17921308Sache 18021308Sache /* Then check hrNetworkTable for this device */ 18121308Sache TAILQ_FOREACH(net, &network_tbl, link) 18221308Sache if (net->index == dev->index) 18321308Sache break; 18421308Sache 18521308Sache if (net == NULL && (net = network_entry_create(dev)) == NULL) 18621308Sache continue; 18721308Sache 18821308Sache net->flags |= HR_NETWORK_FOUND; 18921308Sache net->ifIndex = ifp->index; 19021308Sache } 19121308Sache 192119610Sache network_tick = this_tick; 193119610Sache} 194119610Sache 19521308Sache/** 19621308Sache * Finalization routine for hrNetworkTable. 19721308Sache * It destroys the lists and frees any allocated heap memory. 19821308Sache */ 19921308Sachevoid 20021308Sachefini_network_tbl(void) 20121308Sache{ 20221308Sache struct network_entry *n1; 20321308Sache 20421308Sache while ((n1 = TAILQ_FIRST(&network_tbl)) != NULL) { 20521308Sache TAILQ_REMOVE(&network_tbl, n1, link); 20621308Sache free(n1); 20721308Sache } 20821308Sache} 20921308Sache 21021308Sache/** 21121308Sache * Get the interface list from mibII only at this point to be sure that 21221308Sache * it is there already. 21321308Sache */ 21421308Sachevoid 21521308Sachestart_network_tbl(void) 21621308Sache{ 21721308Sache 21821308Sache mib_refresh_iflist(); 21921308Sache network_get_interfaces(); 22021308Sache} 22121308Sache 22221308Sache/** 22321308Sache * Refresh the table. 22421308Sache */ 22521308Sachestatic void 22621308Sacherefresh_network_tbl(void) 22721308Sache{ 22821308Sache struct network_entry *entry, *entry_tmp; 22921308Sache 23021308Sache if (this_tick - network_tick < network_tbl_refresh) { 23121308Sache HRDBG("no refresh needed"); 23221308Sache return; 23321308Sache } 23421308Sache 23521308Sache /* mark each entry as missing */ 23621308Sache TAILQ_FOREACH(entry, &network_tbl, link) 23721308Sache entry->flags &= ~HR_NETWORK_FOUND; 23821308Sache 23921308Sache network_get_interfaces(); 24021308Sache 24121308Sache /* 24221308Sache * Purge items that disappeared 24321308Sache */ 24421308Sache TAILQ_FOREACH_SAFE(entry, &network_tbl, link, entry_tmp) { 24521308Sache if (!(entry->flags & HR_NETWORK_FOUND)) 24621308Sache network_entry_delete(entry); 24721308Sache } 24821308Sache 24921308Sache HRDBG("refresh DONE"); 25021308Sache} 25121308Sache 25226497Sache/* 253 * This is the implementation for a generated (by our SNMP tool) 254 * function prototype, see hostres_tree.h 255 * It handles the SNMP operations for hrNetworkTable 256 */ 257int 258op_hrNetworkTable(struct snmp_context *ctx __unused, struct snmp_value *value, 259 u_int sub, u_int iidx __unused, enum snmp_op curr_op) 260{ 261 struct network_entry *entry; 262 263 refresh_network_tbl(); 264 265 switch (curr_op) { 266 267 case SNMP_OP_GETNEXT: 268 if ((entry = NEXT_OBJECT_INT(&network_tbl, 269 &value->var, sub)) == NULL) 270 return (SNMP_ERR_NOSUCHNAME); 271 value->var.len = sub + 1; 272 value->var.subs[sub] = entry->index; 273 goto get; 274 275 case SNMP_OP_GET: 276 if ((entry = FIND_OBJECT_INT(&network_tbl, 277 &value->var, sub)) == NULL) 278 return (SNMP_ERR_NOSUCHNAME); 279 goto get; 280 281 case SNMP_OP_SET: 282 if ((entry = FIND_OBJECT_INT(&network_tbl, 283 &value->var, sub)) == NULL) 284 return (SNMP_ERR_NO_CREATION); 285 return (SNMP_ERR_NOT_WRITEABLE); 286 287 case SNMP_OP_ROLLBACK: 288 case SNMP_OP_COMMIT: 289 abort(); 290 } 291 abort(); 292 293 get: 294 switch (value->var.subs[sub - 1]) { 295 296 case LEAF_hrNetworkIfIndex: 297 value->v.integer = entry->ifIndex; 298 return (SNMP_ERR_NOERROR); 299 300 } 301 abort(); 302} 303