Example #1
0
void
netsnmp_access_interface_init(void)
{
    netsnmp_assert(0 == _access_interface_init); /* who is calling twice? */

    if (1 == _access_interface_init)
        return;

    _access_interface_init = 1;

#ifndef NETSNMP_ACCESS_INTERFACE_NOARCH
    {
        netsnmp_container * ifcontainer;

        netsnmp_arch_interface_init();
        
        /*
         * load once to set up ifIndexes
         */
        ifcontainer = netsnmp_access_interface_container_load(NULL, 0);
        if(NULL != ifcontainer)
            netsnmp_access_interface_container_free(ifcontainer, 0);
    }
#endif
}
/**
 * load initial data
 *
 * TODO:350:M: Implement ifTable data load
 * This function will also be called by the cache helper to load
 * the container again (after the container free function has been
 * called to free the previous contents).
 *
 * @param container container to which items should be inserted
 *
 * @retval MFD_SUCCESS              : success.
 * @retval MFD_RESOURCE_UNAVAILABLE : Can't access data source
 * @retval MFD_ERROR                : other error.
 *
 *  This function is called to load the index(es) (and data, optionally)
 *  for the every row in the data set.
 *
 * @remark
 *  While loading the data, the only important thing is the indexes.
 *  If access to your data is cheap/fast (e.g. you have a pointer to a
 *  structure in memory), it would make sense to update the data here.
 *  If, however, the accessing the data invovles more work (e.g. parsing
 *  some other existing data, or peforming calculations to derive the data),
 *  then you can limit yourself to setting the indexes and saving any
 *  information you will need later. Then use the saved information in
 *  ifTable_row_prep() for populating data.
 *
 * @note
 *  If you need consistency between rows (like you want statistics
 *  for each row to be from the same time frame), you should set all
 *  data here.
 *
 */
int
ifTable_container_load(netsnmp_container *container)
{
    netsnmp_container *ifcontainer;

    DEBUGMSGTL(("verbose:ifTable:ifTable_container_load", "called\n"));

    /*
     * TODO:351:M: |-> Load/update data in the ifTable container.
     * loop over your ifTable data, allocate a rowreq context,
     * set the index(es) [and data, optionally] and insert into
     * the container.
     */
    /*
     * ifTable gets its data from the netsnmp_interface API.
     */
    ifcontainer =
        netsnmp_access_interface_container_load(NULL,
                                                NETSNMP_ACCESS_INTERFACE_INIT_NOFLAGS);
    if (NULL == ifcontainer)
        return MFD_RESOURCE_UNAVAILABLE;        /* msg already logged */

    /*
     * we just got a fresh copy of interface data. compare it to
     * what we've already got, and make any adjustements...
     */
    CONTAINER_FOR_EACH(container, (netsnmp_container_obj_func *)
                       _check_interface_entry_for_updates, ifcontainer);

    /*
     * now add any new interfaces
     */
    CONTAINER_FOR_EACH(ifcontainer,
                       (netsnmp_container_obj_func *) _add_new_interface,
                       container);

    /*
     * free the container. we've either claimed each ifentry, or released it,
     * so the dal function doesn't need to clear the container.
     */
    netsnmp_access_interface_container_free(ifcontainer,
                                            NETSNMP_ACCESS_INTERFACE_FREE_DONT_CLEAR);

    DEBUGMSGT(("verbose:ifTable:ifTable_cache_load",
               "%d records\n", CONTAINER_SIZE(container)));

    if (_first_load)
        _first_load = 0;

    return MFD_SUCCESS;
}                               /* ifTable_container_load */
Example #3
0
void
Interface_Scan_Init(void)
{
    /*
     * ifTable container shouldn't change, so we shouldn' have to
     * re-fetch it every time.
     */
    if (NULL != c)
        netsnmp_access_interface_container_free(c, 0);

    c = netsnmp_access_interface_container_load(NULL, 0);
    
    if (NULL != c) {
        if (NULL != it)
            ITERATOR_RELEASE(it);
    
        it = CONTAINER_ITERATOR(c);
    }
   
    if (NULL != it)
        e = (netsnmp_interface_entry*)ITERATOR_FIRST(it);
}
Example #4
0
netsnmp_container*
netsnmp_access_interface_container_load(netsnmp_container* container, u_int load_flags)
{
    int rc;

    DEBUGMSGTL(("access:interface:container", "load\n"));
    netsnmp_assert(1 == _access_interface_init);

    if (NULL == container)
        container = netsnmp_access_interface_container_init(load_flags);
    if (NULL == container) {
        snmp_log(LOG_ERR, "no container specified/found for access_interface\n");
        return NULL;
    }

    rc =  netsnmp_arch_interface_container_load(container, load_flags);
    if (0 != rc) {
        netsnmp_access_interface_container_free(container,
                                                NETSNMP_ACCESS_INTERFACE_FREE_NOFLAGS);
        container = NULL;
    }

    return container;
}
/*
 *
 * @retval  0 success
 * @retval -1 no container specified
 * @retval -2 could not open /proc/net/dev
 * @retval -3 could not create entry (probably malloc)
 */
int
netsnmp_arch_interface_container_load(netsnmp_container* container,
                                      u_int load_flags)
{
    FILE           *devin;
    char            line[256];
    netsnmp_interface_entry *entry = NULL;
    static char     scan_expected = 0;
    int             fd;
#ifdef NETSNMP_ENABLE_IPV6
    netsnmp_container *addr_container;
#endif

    DEBUGMSGTL(("access:interface:container:arch", "load (flags %p)\n",
                load_flags));

    if (NULL == container) {
        snmp_log(LOG_ERR, "no container specified/found for interface\n");
        return -1;
    }

    if (!(devin = fopen("/proc/net/dev", "r"))) {
        DEBUGMSGTL(("access:interface",
                    "Failed to load Interface Table (linux1)\n"));
        snmp_log(LOG_ERR, "cannot open /proc/net/dev ...\n");
        return -2;
    }

    /*
     * create socket for ioctls
     */
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0) {
        snmp_log(LOG_ERR, "could not create socket\n");
        return -2;
    }

#ifdef NETSNMP_ENABLE_IPV6
    /*
     * get ipv6 addresses
     */
    addr_container = netsnmp_access_ipaddress_container_load(NULL, 0);
#endif

    /*
     * Read the first two lines of the file, containing the header
     * This indicates which version of the kernel we're working with,
     * and hence which statistics are actually available.
     *
     * Wes originally suggested parsing the field names in this header
     * to detect the position of individual fields directly,
     * but I suspect this is probably more trouble than it's worth.
     */
    fgets(line, sizeof(line), devin);
    fgets(line, sizeof(line), devin);

    if( 0 == scan_expected ) {
        if (strstr(line, "compressed")) {
            scan_expected = 10;
            DEBUGMSGTL(("access:interface",
                        "using linux 2.2 kernel /proc/net/dev\n"));
        } else {
            scan_expected = 5;
            DEBUGMSGTL(("access:interface",
                        "using linux 2.0 kernel /proc/net/dev\n"));
        }
    }

    /*
     * The rest of the file provides the statistics for each interface.
     * Read in each line in turn, isolate the interface name
     *   and retrieve (or create) the corresponding data structure.
     */
    while (fgets(line, sizeof(line), devin)) {
        char           *stats, *ifstart = line;
        u_int           flags;
        oid             if_index;

        flags = 0;
        if (line[strlen(line) - 1] == '\n')
            line[strlen(line) - 1] = '\0';

        while (*ifstart && *ifstart == ' ')
            ifstart++;

        if ((!*ifstart) || ((stats = strrchr(ifstart, ':')) == NULL)) {
            snmp_log(LOG_ERR,
                     "interface data format error 1, line ==|%s|\n", line);
            continue;
        }
        if ((scan_expected == 10) && ((stats - line) < 6)) {
            snmp_log(LOG_ERR,
                     "interface data format error 2 (%d < 6), line ==|%s|\n",
                     stats - line, line);
        }

        DEBUGMSGTL(("9:access:ifcontainer", "processing '%s'\n", ifstart));

        /*
         * get index via ioctl.
         * If we've met this interface before, use the same index.
         * Otherwise find an unused index value and use that.
         */
        *stats++ = 0; /* null terminate name */

        if_index = netsnmp_arch_interface_index_find(ifstart);

        /*
         * set address type flags.
         * the only way I know of to check an interface for
         * ip version is to look for ip addresses. If anyone
         * knows a better way, put it here!
         */
#ifdef NETSNMP_ENABLE_IPV6
        _arch_interface_has_ipv6(if_index, &flags, addr_container);
#endif
        netsnmp_access_interface_ioctl_has_ipv4(fd, ifstart, 0, &flags);

        /*
         * do we only want one address type?
         */
        if (((load_flags & NETSNMP_ACCESS_INTERFACE_LOAD_IP4_ONLY) &&
             ((flags & NETSNMP_INTERFACE_FLAGS_HAS_IPV4) == 0)) ||
            ((load_flags & NETSNMP_ACCESS_INTERFACE_LOAD_IP6_ONLY) &&
             ((flags & NETSNMP_INTERFACE_FLAGS_HAS_IPV6) == 0))) {
            DEBUGMSGTL(("9:access:ifcontainer",
                        "interface '%s' excluded by ip version\n",
                        ifstart));
            continue;
        }

        entry = netsnmp_access_interface_entry_create(ifstart, 0);
        if(NULL == entry) {
#ifdef NETSNMP_ENABLE_IPV6
            netsnmp_access_ipaddress_container_free(addr_container, 0);
#endif
            netsnmp_access_interface_container_free(container,
                                                    NETSNMP_ACCESS_INTERFACE_FREE_NOFLAGS);
            fclose(devin);
            close(fd);
            return -3;
        }
        entry->ns_flags = flags; /* initial flags; we'll set more later */

        /*
         * xxx-rks: get descr by linking mem from /proc/pci and /proc/iomem
         */


        /*
         * use ioctls for some stuff
         *  (ignore rc, so we get as much info as possible)
         */
        netsnmp_access_interface_ioctl_physaddr_get(fd, entry);

        /*
         * physaddr should have set type. make some guesses (based
         * on name) if not.
         */
        if(0 == entry->type) {
            typedef struct _match_if {
               int             mi_type;
               const char     *mi_name;
            }              *pmatch_if, match_if;
            
            static match_if lmatch_if[] = {
                {IANAIFTYPE_SOFTWARELOOPBACK, "lo"},
                {IANAIFTYPE_ETHERNETCSMACD, "eth"},
                {IANAIFTYPE_ETHERNETCSMACD, "vmnet"},
                {IANAIFTYPE_ISO88025TOKENRING, "tr"},
                {IANAIFTYPE_FASTETHER, "feth"},
                {IANAIFTYPE_GIGABITETHERNET,"gig"},
                {IANAIFTYPE_PPP, "ppp"},
                {IANAIFTYPE_SLIP, "sl"},
                {IANAIFTYPE_TUNNEL, "sit"},
                {IANAIFTYPE_BASICISDN, "ippp"},
                {IANAIFTYPE_PROPVIRTUAL, "bond"}, /* Bonding driver find fastest slave */
                {IANAIFTYPE_PROPVIRTUAL, "vad"},  /* ANS driver - ?speed? */
                {0, 0}                  /* end of list */
            };

            int             ii, len;
            register pmatch_if pm;
            
            for (ii = 0, pm = lmatch_if; pm->mi_name; pm++) {
                len = strlen(pm->mi_name);
                if (0 == strncmp(entry->name, pm->mi_name, len)) {
                    entry->type = pm->mi_type;
                    break;
                }
            }
            if(NULL == pm->mi_name)
                entry->type = IANAIFTYPE_OTHER;
        }

        if (IANAIFTYPE_ETHERNETCSMACD == entry->type)
            entry->speed =
//                    10000000;//incifer 20091027, fix read RTL8306 ocurred error.
                netsnmp_linux_interface_get_if_speed(fd, entry->name);
#ifdef APPLIED_PATCH_836390   /* xxx-rks ifspeed fixes */
        else if (IANAIFTYPE_PROPVIRTUAL == entry->type)
            entry->speed = _get_bonded_if_speed(entry);
#endif
        else
            netsnmp_access_interface_entry_guess_speed(entry);
        
        netsnmp_access_interface_ioctl_flags_get(fd, entry);

        netsnmp_access_interface_ioctl_mtu_get(fd, entry);

        /*
         * Zero speed means link problem.
         * - i'm not sure this is always true...
         */
        if((entry->speed == 0) && (entry->os_flags & IFF_UP)) {
            entry->os_flags &= ~IFF_RUNNING;
        }

        /*
         * check for promiscuous mode.
         *  NOTE: there are 2 ways to set promiscuous mode in Linux
         *  (kernels later than 2.2.something) - using ioctls and
         *  using setsockopt. The ioctl method tested here does not
         *  detect if an interface was set using setsockopt. google
         *  on IFF_PROMISC and linux to see lots of arguments about it.
         */
        if(entry->os_flags & IFF_PROMISC) {
            entry->promiscuous = 1; /* boolean */
        }

        /*
         * hardcoded max packet size
         * (see ip_frag_reasm: if(len > 65535) goto out_oversize;)
         */
        entry->reasm_max_v4 = entry->reasm_max_v6 = 65535;
        entry->ns_flags |= 
            NETSNMP_INTERFACE_FLAGS_HAS_V4_REASMMAX |
            NETSNMP_INTERFACE_FLAGS_HAS_V6_REASMMAX;

        netsnmp_access_interface_entry_overrides(entry);

        entry->speed_high = entry->speed / 1000000;

        if (! (load_flags & NETSNMP_ACCESS_INTERFACE_LOAD_NO_STATS))
            _parse_stats(entry, stats, scan_expected);

        if (flags & NETSNMP_INTERFACE_FLAGS_HAS_IPV4)
            _arch_interface_flags_v4_get(entry);

#ifdef NETSNMP_ENABLE_IPV6
        if (flags & NETSNMP_INTERFACE_FLAGS_HAS_IPV6)
            _arch_interface_flags_v6_get(entry);
#endif /* NETSNMP_ENABLE_IPV6 */

        /*
         * add to container
         */
        CONTAINER_INSERT(container, entry);
    }
#ifdef NETSNMP_ENABLE_IPV6
    netsnmp_access_ipaddress_container_free(addr_container, 0);
#endif
    fclose(devin);
    close(fd);
    return 0;
}