2
* Interface MIB architecture support
4
* $Id: interface_common.c,v 1.20.2.2 2005/02/09 21:02:14 nba Exp $
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"
11
#include <net-snmp/agent/net-snmp-agent-includes.h>
12
#include <net-snmp/library/snmp_enum.h>
13
#include "interface.h"
15
/**---------------------------------------------------------------------*/
19
static netsnmp_conf_if_list *conf_list = NULL;
20
static int need_wrap_check = -1;
21
static int _access_interface_init = 0;
24
* local static prototypes
26
static int _access_interface_entry_compare_name(const void *lhs,
28
static void _access_interface_entry_release(netsnmp_interface_entry * entry,
30
static void _access_interface_entry_save_name(const char *name, oid index);
31
static void _parse_interface_config(const char *token, char *cptr);
32
static void _free_interface_config(void);
34
/**---------------------------------------------------------------------*/
36
* external per-architecture functions prototypes
38
* These shouldn't be called by the general public, so they aren't in
41
#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
42
extern void netsnmp_arch_interface_init(void);
44
netsnmp_arch_interface_container_load(netsnmp_container* container,
47
netsnmp_arch_set_admin_status(netsnmp_interface_entry * entry,
49
extern int netsnmp_arch_interface_index_find(const char*name);
53
/**---------------------------------------------------------------------*/
58
init_interface_common(void)
60
snmpd_register_config_handler("interface", _parse_interface_config,
61
_free_interface_config,
67
netsnmp_access_interface_init(void)
69
netsnmp_assert(0 == _access_interface_init); /* who is calling twice? */
71
if (1 == _access_interface_init)
74
_access_interface_init = 1;
76
#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
78
netsnmp_container * ifcontainer;
80
netsnmp_arch_interface_init();
83
* load once to set up ifIndexes
85
ifcontainer = netsnmp_access_interface_container_load(NULL, 0);
86
if(NULL != ifcontainer)
87
netsnmp_access_interface_container_free(ifcontainer, 0);
92
/**---------------------------------------------------------------------*/
97
* initialize interface container
100
netsnmp_access_interface_container_init(u_int flags)
102
netsnmp_container *container1;
104
DEBUGMSGTL(("access:interface:container", "init\n"));
107
* create the containers. one indexed by ifIndex, the other
110
container1 = netsnmp_container_find("access_interface:table_container");
111
if (NULL == container1)
114
if (flags & NETSNMP_ACCESS_INTERFACE_INIT_ADDL_IDX_BY_NAME) {
115
netsnmp_container *container2 =
116
netsnmp_container_find("access_interface_by_name:access_interface:table_container");
117
if (NULL == container2)
120
container2->compare = _access_interface_entry_compare_name;
122
netsnmp_container_add_index(container1, container2);
129
* load interface information in specified container
131
* @param container empty container, or NULL to have one created for you
132
* @param load_flags flags to modify behaviour. Examples:
133
* NETSNMP_ACCESS_INTERFACE_INIT_ADDL_IDX_BY_NAME
136
* @retval !NULL pointer to container
138
#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
140
netsnmp_access_interface_container_load(netsnmp_container* container, u_int load_flags)
144
DEBUGMSGTL(("access:interface:container", "load\n"));
145
netsnmp_assert(1 == _access_interface_init);
147
if (NULL == container)
148
container = netsnmp_access_interface_container_init(load_flags);
149
if (NULL == container) {
150
snmp_log(LOG_ERR, "no container specified/found for access_interface\n");
154
rc = netsnmp_arch_interface_container_load(container, load_flags);
156
netsnmp_access_interface_container_free(container,
157
NETSNMP_ACCESS_INTERFACE_FREE_NOFLAGS);
165
netsnmp_access_interface_container_free(netsnmp_container *container, u_int free_flags)
167
DEBUGMSGTL(("access:interface:container", "free\n"));
169
if (NULL == container) {
170
snmp_log(LOG_ERR, "invalid container for netsnmp_access_interface_free\n");
174
if(! (free_flags & NETSNMP_ACCESS_INTERFACE_FREE_DONT_CLEAR)) {
178
CONTAINER_CLEAR(container,
179
(netsnmp_container_obj_func*)_access_interface_entry_release,
183
CONTAINER_FREE(container);
187
* @retval 0 interface not found
190
netsnmp_access_interface_index_find(const char *name)
192
DEBUGMSGTL(("access:interface:find", "index\n"));
193
netsnmp_assert(1 == _access_interface_init);
195
return netsnmp_arch_interface_index_find(name);
199
/**---------------------------------------------------------------------*/
205
netsnmp_interface_entry *
206
netsnmp_access_interface_entry_get_by_index(netsnmp_container *container, oid index)
210
DEBUGMSGTL(("access:interface:entry", "by_index\n"));
211
netsnmp_assert(1 == _access_interface_init);
213
if (NULL == container) {
215
"invalid container for netsnmp_access_interface_entry_get_by_index\n");
222
return (netsnmp_interface_entry *) CONTAINER_FIND(container, &tmp);
227
netsnmp_interface_entry *
228
netsnmp_access_interface_entry_get_by_name(netsnmp_container *container,
231
netsnmp_interface_entry tmp;
233
DEBUGMSGTL(("access:interface:entry", "by_name\n"));
234
netsnmp_assert(1 == _access_interface_init);
236
if (NULL == container) {
238
"invalid container for netsnmp_access_interface_entry_get_by_name\n");
242
if (NULL == container->next) {
244
"secondary index missing for netsnmp_access_interface_entry_get_by_name\n");
249
return CONTAINER_FIND(container->next, &tmp);
253
* @retval NULL index not found
256
netsnmp_access_interface_name_find(oid index)
258
DEBUGMSGTL(("access:interface:find", "name\n"));
259
netsnmp_assert(1 == _access_interface_init);
261
return se_find_label_in_slist("interfaces", index);
266
netsnmp_interface_entry *
267
netsnmp_access_interface_entry_create(const char *name, oid if_index)
269
netsnmp_interface_entry *entry =
270
SNMP_MALLOC_TYPEDEF(netsnmp_interface_entry);
272
DEBUGMSGTL(("access:interface:entry", "create\n"));
273
netsnmp_assert(1 == _access_interface_init);
279
entry->name = strdup(name);
282
* get if index, and save name for reverse lookup
284
#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
286
entry->index = netsnmp_access_interface_index_find(name);
289
entry->index = if_index;
290
_access_interface_entry_save_name(name, entry->index);
293
* until we can get actual description, leave descr NULL.
294
* The end user can decide what to do with it.
296
/* entry->descr = strdup("unknown"); */
299
* make some assumptions
301
entry->connector_present = 1;
303
entry->oid_index.len = 1;
304
entry->oid_index.oids = (oid *) & entry->index;
312
netsnmp_access_interface_entry_free(netsnmp_interface_entry * entry)
314
DEBUGMSGTL(("access:interface:entry", "free\n"));
320
* SNMP_FREE not needed, for any of these,
321
* since the whole entry is about to be freed
324
if (NULL != entry->old_stats)
325
free(entry->old_stats);
327
if (NULL != entry->name)
330
if (NULL != entry->descr)
333
if (NULL != entry->paddr)
341
* @retval 0 : success
342
* @retval < 0 : error
344
#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
346
netsnmp_access_interface_entry_set_admin_status(netsnmp_interface_entry * entry,
351
DEBUGMSGTL(("access:interface:entry", "set_admin_status\n"));
356
if ((ifAdminStatus < IFADMINSTATUS_UP) ||
357
(ifAdminStatus > IFADMINSTATUS_TESTING))
360
rc = netsnmp_arch_set_admin_status(entry, ifAdminStatus);
361
if (0 == rc) /* success */
362
entry->admin_status = ifAdminStatus;
368
/**---------------------------------------------------------------------*/
376
_access_interface_entry_compare_name(const void *lhs, const void *rhs)
378
return strcmp(((const netsnmp_interface_entry *) lhs)->name,
379
((const netsnmp_interface_entry *) rhs)->name);
385
_access_interface_entry_release(netsnmp_interface_entry * entry, void *context)
387
netsnmp_access_interface_entry_free(entry);
393
_access_interface_entry_save_name(const char *name, oid index)
400
tmp = se_find_value_in_slist("interfaces", name);
402
se_add_pair_to_slist("interfaces", strdup(name), index);
403
DEBUGMSGTL(("access:interface:ifIndex", "saved ifIndex %d for %s\n",
407
netsnmp_assert(index == tmp);
413
* @retval 0 : success
417
netsnmp_access_interface_entry_update_stats(netsnmp_interface_entry * prev_vals,
418
netsnmp_interface_entry * new_vals)
420
DEBUGMSGTL(("access:interface", "check_wrap\n"));
425
if ((NULL == prev_vals) || (NULL == new_vals) ||
426
(NULL == prev_vals->name) || (NULL == new_vals->name) ||
427
(0 != strncmp(prev_vals->name, new_vals->name, strlen(prev_vals->name))))
431
* if we've determined that we have 64 bit counters, just copy them.
433
if (0 == need_wrap_check) {
434
memcpy(&prev_vals->stats, &new_vals->stats, sizeof(new_vals->stats));
438
if (NULL == prev_vals->old_stats) {
440
* if we don't have old stats, copy previous stats
442
prev_vals->old_stats = SNMP_MALLOC_TYPEDEF(netsnmp_interface_stats);
443
if (NULL == prev_vals->old_stats) {
446
memcpy(prev_vals->old_stats, &prev_vals->stats, sizeof(new_vals->stats));
449
netsnmp_c64_check32_and_update(&prev_vals->stats.ibytes,
450
&new_vals->stats.ibytes,
451
&prev_vals->old_stats->ibytes,
453
netsnmp_c64_check32_and_update(&prev_vals->stats.iucast,
454
&new_vals->stats.iucast,
455
&prev_vals->old_stats->iucast,
457
netsnmp_c64_check32_and_update(&prev_vals->stats.imcast,
458
&new_vals->stats.imcast,
459
&prev_vals->old_stats->imcast,
461
netsnmp_c64_check32_and_update(&prev_vals->stats.ibcast,
462
&new_vals->stats.ibcast,
463
&prev_vals->old_stats->ibcast,
465
netsnmp_c64_check32_and_update(&prev_vals->stats.obytes,
466
&new_vals->stats.obytes,
467
&prev_vals->old_stats->obytes,
469
netsnmp_c64_check32_and_update(&prev_vals->stats.oucast,
470
&new_vals->stats.oucast,
471
&prev_vals->old_stats->oucast,
473
netsnmp_c64_check32_and_update(&prev_vals->stats.omcast,
474
&new_vals->stats.omcast,
475
&prev_vals->old_stats->omcast,
477
netsnmp_c64_check32_and_update(&prev_vals->stats.obcast,
478
&new_vals->stats.obcast,
479
&prev_vals->old_stats->obcast,
483
* if we've decided we no longer need to check wraps, free old stats
485
if (0 == need_wrap_check) {
486
SNMP_FREE(prev_vals->old_stats);
490
* update old stats from new stats.
491
* careful - old_stats is a pointer to stats...
493
memcpy(prev_vals->old_stats, &new_vals->stats, sizeof(new_vals->stats));
500
* copy interface entry data (after checking for counter wraps)
502
* @retval -2 : malloc failed
503
* @retval -1 : interfaces not the same
504
* @retval 0 : no error
507
netsnmp_access_interface_entry_copy(netsnmp_interface_entry * lhs,
508
netsnmp_interface_entry * rhs)
510
DEBUGMSGTL(("access:interface", "copy\n"));
512
if ((NULL == lhs) || (NULL == rhs) ||
513
(NULL == lhs->name) || (NULL == rhs->name) ||
514
(0 != strncmp(lhs->name, rhs->name, strlen(rhs->name))))
520
netsnmp_access_interface_entry_update_stats(lhs, rhs);
525
lhs->ns_flags = rhs->ns_flags;
526
if((NULL != lhs->descr) && (NULL != rhs->descr) &&
527
(0 == strcmp(lhs->descr, rhs->descr)))
530
if (NULL != lhs->descr)
531
SNMP_FREE(lhs->descr);
533
lhs->descr = strdup(rhs->descr);
534
if(NULL == lhs->descr)
538
lhs->type = rhs->type;
539
lhs->speed = rhs->speed;
540
lhs->speed_high = rhs->speed_high;
542
lhs->discontinuity = rhs->discontinuity;
543
lhs->oper_status = rhs->oper_status;
544
lhs->promiscuous = rhs->promiscuous;
545
lhs->connector_present = rhs->connector_present;
546
lhs->os_flags = rhs->os_flags;
547
if(lhs->paddr_len == rhs->paddr_len) {
549
memcpy(lhs->paddr,rhs->paddr,rhs->paddr_len);
551
if (NULL != lhs->paddr)
552
SNMP_FREE(lhs->paddr);
554
lhs->paddr = malloc(rhs->paddr_len);
555
if(NULL == lhs->paddr)
557
memcpy(lhs->paddr,rhs->paddr,rhs->paddr_len);
560
lhs->paddr_len = rhs->paddr_len;
566
netsnmp_access_interface_entry_guess_speed(netsnmp_interface_entry *entry)
568
if (entry->type == IANAIFTYPE_ETHERNETCSMACD)
569
entry->speed = 10000000;
570
else if (entry->type == IANAIFTYPE_SOFTWARELOOPBACK)
571
entry->speed = 10000000;
572
else if (entry->type == IANAIFTYPE_ISO88025TOKENRING)
573
entry->speed = 4000000;
578
netsnmp_conf_if_list *
579
netsnmp_access_interface_entry_overrides_get(const char * name)
581
netsnmp_conf_if_list * if_ptr;
583
netsnmp_assert(1 == _access_interface_init);
587
for (if_ptr = conf_list; if_ptr; if_ptr = if_ptr->next)
588
if (!strcmp(if_ptr->name, name))
595
netsnmp_access_interface_entry_overrides(netsnmp_interface_entry *entry)
597
netsnmp_conf_if_list * if_ptr;
599
netsnmp_assert(1 == _access_interface_init);
604
* enforce mib size limit
606
if(entry->descr && (strlen(entry->descr) > 255))
607
entry->descr[255] = 0;
610
netsnmp_access_interface_entry_overrides_get(entry->name);
612
entry->type = if_ptr->type;
613
entry->speed = if_ptr->speed;
617
/**---------------------------------------------------------------------*/
619
* interface config token
624
_parse_interface_config(const char *token, char *cptr)
626
netsnmp_conf_if_list *if_ptr, *if_new;
627
char *name, *type, *speed, *ecp;
630
name = strtok_r(cptr, " \t", &st);
632
config_perror("Missing NAME parameter");
635
type = strtok_r(NULL, " \t", &st);
637
config_perror("Missing TYPE parameter");
640
speed = strtok_r(NULL, " \t", &st);
642
config_perror("Missing SPEED parameter");
647
if (strcmp(if_ptr->name, name))
648
if_ptr = if_ptr->next;
652
config_pwarn("Duplicate interface specification");
653
if_new = SNMP_MALLOC_TYPEDEF(netsnmp_conf_if_list);
655
config_perror("Out of memory");
658
if_new->speed = strtoul(speed, &ecp, 0);
660
config_perror("Bad SPEED value");
664
if_new->type = strtol(type, &ecp, 0);
665
if (*ecp || if_new->type < 0) {
666
config_perror("Bad TYPE");
670
if_new->name = strdup(name);
672
config_perror("Out of memory");
676
if_new->next = conf_list;
681
_free_interface_config(void)
683
netsnmp_conf_if_list *if_ptr = conf_list, *if_next;
685
if_next = if_ptr->next;