2
* Interface MIB architecture support
4
* $Id: interface.c 17263 2008-10-16 09:56:01Z jsafranek $
6
#include <net-snmp/net-snmp-config.h>
7
#include <net-snmp/net-snmp-includes.h>
8
#include "mibII/mibII_common.h"
9
#include "if-mib/ifTable/ifTable_constants.h"
10
#include "if-mib/data_access/interface.h"
12
#include <net-snmp/agent/net-snmp-agent-includes.h>
13
#include <net-snmp/library/snmp_enum.h>
14
#include <net-snmp/data_access/interface.h>
17
/**---------------------------------------------------------------------*/
21
static netsnmp_conf_if_list *conf_list = NULL;
22
static int need_wrap_check = -1;
23
static int _access_interface_init = 0;
26
* local static prototypes
28
static int _access_interface_entry_compare_name(const void *lhs,
30
#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
31
static void _access_interface_entry_release(netsnmp_interface_entry * entry,
34
static void _access_interface_entry_save_name(const char *name, oid index);
35
static void _parse_interface_config(const char *token, char *cptr);
36
static void _free_interface_config(void);
38
/**---------------------------------------------------------------------*/
40
* external per-architecture functions prototypes
42
* These shouldn't be called by the general public, so they aren't in
45
#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
46
extern void netsnmp_arch_interface_init(void);
48
netsnmp_arch_interface_container_load(netsnmp_container* container,
51
netsnmp_arch_set_admin_status(netsnmp_interface_entry * entry,
53
extern int netsnmp_arch_interface_index_find(const char*name);
63
snmpd_register_config_handler("interface", _parse_interface_config,
64
_free_interface_config,
70
netsnmp_access_interface_init(void)
72
netsnmp_assert(0 == _access_interface_init); /* who is calling twice? */
74
if (1 == _access_interface_init)
77
_access_interface_init = 1;
79
#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
81
netsnmp_container * ifcontainer;
83
netsnmp_arch_interface_init();
86
* load once to set up ifIndexes
88
ifcontainer = netsnmp_access_interface_container_load(NULL, 0);
89
if(NULL != ifcontainer)
90
netsnmp_access_interface_container_free(ifcontainer, 0);
95
/**---------------------------------------------------------------------*/
100
* initialize interface container
103
netsnmp_access_interface_container_init(u_int flags)
105
netsnmp_container *container1;
107
DEBUGMSGTL(("access:interface:container", "init\n"));
110
* create the containers. one indexed by ifIndex, the other
113
container1 = netsnmp_container_find("access_interface:table_container");
114
if (NULL == container1)
117
container1->container_name = strdup("interface container");
118
if (flags & NETSNMP_ACCESS_INTERFACE_INIT_ADDL_IDX_BY_NAME) {
119
netsnmp_container *container2 =
120
netsnmp_container_find("access_interface_by_name:access_interface:table_container");
121
if (NULL == container2)
124
container2->container_name = strdup("interface name container");
125
container2->compare = _access_interface_entry_compare_name;
127
netsnmp_container_add_index(container1, container2);
134
* load interface information in specified container
136
* @param container empty container, or NULL to have one created for you
137
* @param load_flags flags to modify behaviour. Examples:
138
* NETSNMP_ACCESS_INTERFACE_INIT_ADDL_IDX_BY_NAME
141
* @retval !NULL pointer to container
143
#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
145
netsnmp_access_interface_container_load(netsnmp_container* container, u_int load_flags)
149
DEBUGMSGTL(("access:interface:container", "load\n"));
150
netsnmp_assert(1 == _access_interface_init);
152
if (NULL == container)
153
container = netsnmp_access_interface_container_init(load_flags);
154
if (NULL == container) {
155
snmp_log(LOG_ERR, "no container specified/found for access_interface\n");
159
rc = netsnmp_arch_interface_container_load(container, load_flags);
161
netsnmp_access_interface_container_free(container,
162
NETSNMP_ACCESS_INTERFACE_FREE_NOFLAGS);
170
netsnmp_access_interface_container_free(netsnmp_container *container, u_int free_flags)
172
DEBUGMSGTL(("access:interface:container", "free\n"));
174
if (NULL == container) {
175
snmp_log(LOG_ERR, "invalid container for netsnmp_access_interface_free\n");
179
if(! (free_flags & NETSNMP_ACCESS_INTERFACE_FREE_DONT_CLEAR)) {
183
CONTAINER_CLEAR(container,
184
(netsnmp_container_obj_func*)_access_interface_entry_release,
188
CONTAINER_FREE(container);
192
* @retval 0 interface not found
195
netsnmp_access_interface_index_find(const char *name)
197
DEBUGMSGTL(("access:interface:find", "index\n"));
198
netsnmp_assert(1 == _access_interface_init);
200
return netsnmp_arch_interface_index_find(name);
204
/**---------------------------------------------------------------------*/
210
netsnmp_interface_entry *
211
netsnmp_access_interface_entry_get_by_index(netsnmp_container *container, oid index)
215
DEBUGMSGTL(("access:interface:entry", "by_index\n"));
216
netsnmp_assert(1 == _access_interface_init);
218
if (NULL == container) {
220
"invalid container for netsnmp_access_interface_entry_get_by_index\n");
227
return (netsnmp_interface_entry *) CONTAINER_FIND(container, &tmp);
232
netsnmp_interface_entry *
233
netsnmp_access_interface_entry_get_by_name(netsnmp_container *container,
236
netsnmp_interface_entry tmp;
238
DEBUGMSGTL(("access:interface:entry", "by_name\n"));
239
netsnmp_assert(1 == _access_interface_init);
241
if (NULL == container) {
243
"invalid container for netsnmp_access_interface_entry_get_by_name\n");
247
if (NULL == container->next) {
249
"secondary index missing for netsnmp_access_interface_entry_get_by_name\n");
253
tmp.name = (char *)name;
254
return CONTAINER_FIND(container->next, &tmp);
258
* @retval NULL index not found
261
netsnmp_access_interface_name_find(oid index)
263
DEBUGMSGTL(("access:interface:find", "name\n"));
264
netsnmp_assert(1 == _access_interface_init);
266
return se_find_label_in_slist("interfaces", index);
271
netsnmp_interface_entry *
272
netsnmp_access_interface_entry_create(const char *name, oid if_index)
274
netsnmp_interface_entry *entry =
275
SNMP_MALLOC_TYPEDEF(netsnmp_interface_entry);
277
DEBUGMSGTL(("access:interface:entry", "create\n"));
278
netsnmp_assert(1 == _access_interface_init);
284
entry->name = strdup(name);
287
* get if index, and save name for reverse lookup
289
#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
291
entry->index = netsnmp_access_interface_index_find(name);
294
entry->index = if_index;
295
_access_interface_entry_save_name(name, entry->index);
297
entry->descr = strdup(name);
300
* make some assumptions
302
entry->connector_present = 1;
304
entry->oid_index.len = 1;
305
entry->oid_index.oids = (oid *) & entry->index;
313
netsnmp_access_interface_entry_free(netsnmp_interface_entry * entry)
315
DEBUGMSGTL(("access:interface:entry", "free\n"));
321
* SNMP_FREE not needed, for any of these,
322
* since the whole entry is about to be freed
325
if (NULL != entry->old_stats)
326
free(entry->old_stats);
328
if (NULL != entry->name)
331
if (NULL != entry->descr)
334
if (NULL != entry->paddr)
341
* Blech - backwards compatible mibII/interfaces style interface
342
* functions, so we don't have to update older modules to use
343
* the new code to get correct ifIndex values.
345
#if defined( USING_IF_MIB_IFTABLE_IFTABLE_DATA_ACCESS_MODULE ) && \
346
! defined( NETSNMP_NO_BACKWARDS_COMPATABILITY )
348
static netsnmp_iterator *it = NULL;
349
static netsnmp_container *c = NULL;
350
static netsnmp_interface_entry *e = NULL;
356
Interface_Scan_Init(void)
359
* ifTable container shouldn't change, so we shouldn' have to
360
* re-fetch it every time.
363
netsnmp_access_interface_container_free(c, 0);
365
c = netsnmp_access_interface_container_load(NULL, 0);
369
ITERATOR_RELEASE(it);
371
it = CONTAINER_ITERATOR(c);
375
e = ITERATOR_FIRST(it);
379
Interface_Scan_Next(short *index, char *name, netsnmp_interface_entry **entry,
389
strcpy(name, e->name);
394
e = ITERATOR_NEXT(it);
398
#endif /* NETSNMP_NO_BACKWARDS_COMPATABILITY */
403
* @retval 0 : success
404
* @retval < 0 : error
406
#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
408
netsnmp_access_interface_entry_set_admin_status(netsnmp_interface_entry * entry,
413
DEBUGMSGTL(("access:interface:entry", "set_admin_status\n"));
418
if ((ifAdminStatus < IFADMINSTATUS_UP) ||
419
(ifAdminStatus > IFADMINSTATUS_TESTING))
422
rc = netsnmp_arch_set_admin_status(entry, ifAdminStatus);
423
if (0 == rc) /* success */
424
entry->admin_status = ifAdminStatus;
430
/**---------------------------------------------------------------------*/
438
_access_interface_entry_compare_name(const void *lhs, const void *rhs)
440
return strcmp(((const netsnmp_interface_entry *) lhs)->name,
441
((const netsnmp_interface_entry *) rhs)->name);
447
_access_interface_entry_release(netsnmp_interface_entry * entry, void *context)
449
netsnmp_access_interface_entry_free(entry);
455
_access_interface_entry_save_name(const char *name, oid index)
462
tmp = se_find_value_in_slist("interfaces", name);
464
se_add_pair_to_slist("interfaces", strdup(name), index);
465
DEBUGMSGTL(("access:interface:ifIndex", "saved ifIndex %d for %s\n",
470
static int logged = 0;
472
snmp_log(LOG_ERR, "IfIndex of an interface changed. Such " \
473
"interfaces will appear multiple times in IF-MIB.\n");
476
DEBUGMSGTL(("access:interface:ifIndex", "index %d != tmp for %s\n",
484
* @retval 0 : success
488
netsnmp_access_interface_entry_update_stats(netsnmp_interface_entry * prev_vals,
489
netsnmp_interface_entry * new_vals)
491
DEBUGMSGTL(("access:interface", "check_wrap\n"));
496
if ((NULL == prev_vals) || (NULL == new_vals) ||
497
(NULL == prev_vals->name) || (NULL == new_vals->name) ||
498
(0 != strncmp(prev_vals->name, new_vals->name, strlen(prev_vals->name))))
502
* if we've determined that we have 64 bit counters, just copy them.
504
if (0 == need_wrap_check) {
505
memcpy(&prev_vals->stats, &new_vals->stats, sizeof(new_vals->stats));
509
if (NULL == prev_vals->old_stats) {
511
* if we don't have old stats, copy previous stats
513
prev_vals->old_stats = SNMP_MALLOC_TYPEDEF(netsnmp_interface_stats);
514
if (NULL == prev_vals->old_stats) {
517
memcpy(prev_vals->old_stats, &prev_vals->stats, sizeof(new_vals->stats));
520
netsnmp_c64_check32_and_update(&prev_vals->stats.ibytes,
521
&new_vals->stats.ibytes,
522
&prev_vals->old_stats->ibytes,
524
netsnmp_c64_check32_and_update(&prev_vals->stats.iucast,
525
&new_vals->stats.iucast,
526
&prev_vals->old_stats->iucast,
528
netsnmp_c64_check32_and_update(&prev_vals->stats.imcast,
529
&new_vals->stats.imcast,
530
&prev_vals->old_stats->imcast,
532
netsnmp_c64_check32_and_update(&prev_vals->stats.ibcast,
533
&new_vals->stats.ibcast,
534
&prev_vals->old_stats->ibcast,
536
netsnmp_c64_check32_and_update(&prev_vals->stats.obytes,
537
&new_vals->stats.obytes,
538
&prev_vals->old_stats->obytes,
540
netsnmp_c64_check32_and_update(&prev_vals->stats.oucast,
541
&new_vals->stats.oucast,
542
&prev_vals->old_stats->oucast,
544
netsnmp_c64_check32_and_update(&prev_vals->stats.omcast,
545
&new_vals->stats.omcast,
546
&prev_vals->old_stats->omcast,
548
netsnmp_c64_check32_and_update(&prev_vals->stats.obcast,
549
&new_vals->stats.obcast,
550
&prev_vals->old_stats->obcast,
554
* Copy 32 bit counters
556
prev_vals->stats.ierrors = new_vals->stats.ierrors;
557
prev_vals->stats.idiscards = new_vals->stats.idiscards;
558
prev_vals->stats.iunknown_protos = new_vals->stats.iunknown_protos;
559
prev_vals->stats.inucast = new_vals->stats.inucast;
560
prev_vals->stats.oerrors = new_vals->stats.oerrors;
561
prev_vals->stats.odiscards = new_vals->stats.odiscards;
562
prev_vals->stats.oqlen = new_vals->stats.oqlen;
563
prev_vals->stats.collisions = new_vals->stats.collisions;
564
prev_vals->stats.onucast = new_vals->stats.onucast;
567
* if we've decided we no longer need to check wraps, free old stats
569
if (0 == need_wrap_check) {
570
SNMP_FREE(prev_vals->old_stats);
574
* update old stats from new stats.
575
* careful - old_stats is a pointer to stats...
577
memcpy(prev_vals->old_stats, &new_vals->stats, sizeof(new_vals->stats));
584
* copy interface entry data (after checking for counter wraps)
586
* @retval -2 : malloc failed
587
* @retval -1 : interfaces not the same
588
* @retval 0 : no error
591
netsnmp_access_interface_entry_copy(netsnmp_interface_entry * lhs,
592
netsnmp_interface_entry * rhs)
594
DEBUGMSGTL(("access:interface", "copy\n"));
596
if ((NULL == lhs) || (NULL == rhs) ||
597
(NULL == lhs->name) || (NULL == rhs->name) ||
598
(0 != strncmp(lhs->name, rhs->name, strlen(rhs->name))))
604
netsnmp_access_interface_entry_update_stats(lhs, rhs);
609
lhs->ns_flags = rhs->ns_flags;
610
if((NULL != lhs->descr) && (NULL != rhs->descr) &&
611
(0 == strcmp(lhs->descr, rhs->descr)))
614
if (NULL != lhs->descr)
615
SNMP_FREE(lhs->descr);
617
lhs->descr = strdup(rhs->descr);
618
if(NULL == lhs->descr)
622
lhs->type = rhs->type;
623
lhs->speed = rhs->speed;
624
lhs->speed_high = rhs->speed_high;
625
lhs->retransmit_v6 = rhs->retransmit_v6;
626
lhs->retransmit_v4 = rhs->retransmit_v4;
627
lhs->reachable_time = rhs->reachable_time;
629
lhs->lastchange = rhs->lastchange;
630
lhs->discontinuity = rhs->discontinuity;
631
lhs->reasm_max_v4 = rhs->reasm_max_v4;
632
lhs->reasm_max_v6 = rhs->reasm_max_v6;
633
lhs->admin_status = rhs->admin_status;
634
lhs->oper_status = rhs->oper_status;
635
lhs->promiscuous = rhs->promiscuous;
636
lhs->connector_present = rhs->connector_present;
637
lhs->forwarding_v6 = rhs->forwarding_v6;
638
lhs->os_flags = rhs->os_flags;
639
if(lhs->paddr_len == rhs->paddr_len) {
641
memcpy(lhs->paddr,rhs->paddr,rhs->paddr_len);
643
if (NULL != lhs->paddr)
644
SNMP_FREE(lhs->paddr);
646
lhs->paddr = malloc(rhs->paddr_len);
647
if(NULL == lhs->paddr)
649
memcpy(lhs->paddr,rhs->paddr,rhs->paddr_len);
652
lhs->paddr_len = rhs->paddr_len;
658
netsnmp_access_interface_entry_guess_speed(netsnmp_interface_entry *entry)
660
if (entry->type == IANAIFTYPE_ETHERNETCSMACD)
661
entry->speed = 10000000;
662
else if (entry->type == IANAIFTYPE_SOFTWARELOOPBACK)
663
entry->speed = 10000000;
664
else if (entry->type == IANAIFTYPE_ISO88025TOKENRING)
665
entry->speed = 4000000;
668
entry->speed_high = entry->speed / 1000000LL;
671
netsnmp_conf_if_list *
672
netsnmp_access_interface_entry_overrides_get(const char * name)
674
netsnmp_conf_if_list * if_ptr;
676
netsnmp_assert(1 == _access_interface_init);
680
for (if_ptr = conf_list; if_ptr; if_ptr = if_ptr->next)
681
if (!strcmp(if_ptr->name, name))
688
netsnmp_access_interface_entry_overrides(netsnmp_interface_entry *entry)
690
netsnmp_conf_if_list * if_ptr;
692
netsnmp_assert(1 == _access_interface_init);
697
* enforce mib size limit
699
if(entry->descr && (strlen(entry->descr) > 255))
700
entry->descr[255] = 0;
703
netsnmp_access_interface_entry_overrides_get(entry->name);
705
entry->type = if_ptr->type;
706
if (if_ptr->speed > 0xffffffff) {
707
entry->speed = 0xffffffff;
709
entry->speed = if_ptr->speed;
711
entry->speed_high = if_ptr->speed / 1000000LL;
715
/**---------------------------------------------------------------------*/
717
* interface config token
722
_parse_interface_config(const char *token, char *cptr)
724
netsnmp_conf_if_list *if_ptr, *if_new;
725
char *name, *type, *speed, *ecp;
728
name = strtok_r(cptr, " \t", &st);
730
config_perror("Missing NAME parameter");
733
type = strtok_r(NULL, " \t", &st);
735
config_perror("Missing TYPE parameter");
738
speed = strtok_r(NULL, " \t", &st);
740
config_perror("Missing SPEED parameter");
745
if (strcmp(if_ptr->name, name))
746
if_ptr = if_ptr->next;
750
config_pwarn("Duplicate interface specification");
751
if_new = SNMP_MALLOC_TYPEDEF(netsnmp_conf_if_list);
753
config_perror("Out of memory");
756
if_new->speed = strtoull(speed, &ecp, 0);
758
config_perror("Bad SPEED value");
762
if_new->type = strtol(type, &ecp, 0);
763
if (*ecp || if_new->type < 0) {
764
config_perror("Bad TYPE");
768
if_new->name = strdup(name);
770
config_perror("Out of memory");
774
if_new->next = conf_list;
779
_free_interface_config(void)
781
netsnmp_conf_if_list *if_ptr = conf_list, *if_next;
783
if_next = if_ptr->next;