Beispiel #1
0
int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
{
    int status, i;

    status = sigar_cpu_list_get(sigar, &sigar->cpulist);

    if (status != SIGAR_OK) {
        return status;
    }

    SIGAR_ZERO(cpu);

    for (i=0; i<sigar->cpulist.number; i++) {
        sigar_cpu_t *xcpu = &sigar->cpulist.data[i];

        cpu->user  += xcpu->user;
        cpu->sys   += xcpu->sys;
        cpu->idle  += xcpu->idle;
        cpu->nice  += xcpu->nice;
        cpu->wait  += xcpu->wait;
        cpu->total += xcpu->total;
    }

    return SIGAR_OK;
}
Beispiel #2
0
/* XXX: check for stale-ness using start_time */
SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid,
                                      sigar_proc_cpu_t *proccpu)
{
    sigar_cache_entry_t *entry;
    sigar_proc_cpu_t *prev;
    sigar_uint64_t otime, time_now = sigar_time_now_millis();
    sigar_uint64_t time_diff, total_diff;
    int status;

    if (!sigar->proc_cpu) {
        sigar->proc_cpu = sigar_cache_new(128);
    }

    entry = sigar_cache_get(sigar->proc_cpu, pid);
    if (entry->value) {
        prev = (sigar_proc_cpu_t *)entry->value;
    }
    else {
        prev = entry->value = malloc(sizeof(*prev));
        SIGAR_ZERO(prev);
    }

    time_diff = time_now - prev->last_time;
    proccpu->last_time = prev->last_time = time_now;

    if (time_diff == 0) {
        /* we were just called within < 1 second ago. */
        memcpy(proccpu, prev, sizeof(*proccpu));
        return SIGAR_OK;
    }

    otime = prev->total;

    status =
        sigar_proc_time_get(sigar, pid,
                            (sigar_proc_time_t *)proccpu);

    if (status != SIGAR_OK) {
        return status;
    }

    memcpy(prev, proccpu, sizeof(*prev));

    if (proccpu->total < otime) {
        /* XXX this should not happen */
        otime = 0;
    }

    if (otime == 0) {
        proccpu->percent = 0.0;
        /* first time called */
        return SIGAR_OK;
    }

    total_diff = proccpu->total - otime;
    proccpu->percent = total_diff / (double)time_diff;

    return SIGAR_OK;
}
Beispiel #3
0
static int net_conn_get_udp_listen(sigar_net_connection_walker_t *walker)
{
    sigar_t *sigar = walker->sigar;
    int flags = walker->flags;
    int status, count, i;
    unsigned int len;
    mib_udpLsnEnt *entries;
    struct nmparms parms;

    len = sizeof(count);
    parms.objid = ID_udpLsnNumEnt;
    parms.buffer = &count;
    parms.len = &len;

    if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
        return status;
    }

    if (count <= 0) {
        return ENOENT;
    }

    len =  count * sizeof(*entries);
    entries = malloc(len);
    parms.objid = ID_udpLsnTable;
    parms.buffer = entries;
    parms.len = &len;

    if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
        free(entries);
        return status;
    }

    for (i=0; i<count; i++) {
        sigar_net_connection_t conn;
        mib_udpLsnEnt *entry = &entries[i];

        SIGAR_ZERO(&conn);

        conn.type = SIGAR_NETCONN_UDP;

        conn.local_port  = (unsigned short)entry->LocalPort;
        conn.remote_port = 0;

        sigar_net_address_set(conn.local_address,
                              entry->LocalAddress);

        sigar_net_address_set(conn.remote_address, 0);

        conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;

        if (walker->add_connection(walker, &conn) != SIGAR_OK) {
            break;
        }
    }

    free(entries);
    return SIGAR_OK;
}
Beispiel #4
0
int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
{
    kstat_ctl_t *kc = sigar->kc;
    kstat_t *ksp;
    sigar_uint64_t kern = 0;

    SIGAR_ZERO(mem);

    /* XXX: is mem hot swappable or can we just do this during open ? */
    mem->total = sysconf(_SC_PHYS_PAGES);
    mem->total <<= sigar->pagesize;

    if (sigar_kstat_update(sigar) == -1) {
        return errno;
    }

    if ((ksp = sigar->ks.syspages) && kstat_read(kc, ksp, NULL) >= 0) {
        sigar_koffsets_init_syspages(sigar, ksp);

        mem->free = kSYSPAGES(KSTAT_SYSPAGES_FREE);
        mem->free <<= sigar->pagesize;

        mem->used = mem->total - mem->free;
    }

    if ((ksp = sigar->ks.mempages) && kstat_read(kc, ksp, NULL) >= 0) {
        sigar_koffsets_init_mempages(sigar, ksp);
    }

    /* XXX mdb ::memstat cachelist/freelist not available to kstat, see: */
    /* http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6821980 */

    /* ZFS ARC cache. see: http://opensolaris.org/jive/thread.jspa?messageID=393695 */
    if ((ksp = kstat_lookup(sigar->kc, "zfs", 0, "arcstats")) &&
        (kstat_read(sigar->kc, ksp, NULL) != -1))
    {
        kstat_named_t *kn;

        if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "size"))) {
            kern = kn->value.i64;
        }
        if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "c_min"))) {
            /* c_min cannot be reclaimed they say */
            if (kern > kn->value.i64) {
                kern -= kn->value.i64;
            }
        }
    }

    mem->actual_free = mem->free + kern;
    mem->actual_used = mem->used - kern;

    sigar_mem_calc_ram(sigar, mem);

    return SIGAR_OK;
}
Beispiel #5
0
static int udp_connection_get(sigar_net_connection_walker_t *walker,
                              struct mib2_udpEntry *entry,
                              int len)
{
    int flags = walker->flags;
    int status;
    char *end = (char *)entry + len;

    while ((char *)entry < end) {
        int state = entry->udpEntryInfo.ue_state;

        /* XXX dunno if this state check is right */
        if (((flags & SIGAR_NETCONN_SERVER) && (state == MIB2_UDP_idle)) ||
            ((flags & SIGAR_NETCONN_CLIENT) && (state != MIB2_UDP_idle)))
        {
            sigar_net_connection_t conn;

            SIGAR_ZERO(&conn);

            sigar_net_address_set(conn.local_address, entry->udpLocalAddress);
            sigar_net_address_set(conn.remote_address, 0);

            conn.local_port = entry->udpLocalPort;
            conn.remote_port = 0;
            conn.type = SIGAR_NETCONN_UDP;

            status = walker->add_connection(walker, &conn);
            if (status != SIGAR_OK) {
                return status;
            }
        }

        entry++;
    }

    return SIGAR_OK;
}
Beispiel #6
0
Datei: peb.c Projekt: 40a/sigar
static int sigar_pbi_get(sigar_t *sigar, HANDLE proc, PEB *peb)
{
    int status;
    PROCESS_BASIC_INFORMATION pbi;
    DWORD size=sizeof(pbi);

    dllmod_init_ntdll(sigar);

    if (!sigar_NtQueryInformationProcess) {
        return SIGAR_ENOTIMPL;
    }

    SIGAR_ZERO(&pbi);
    status =
        sigar_NtQueryInformationProcess(proc,
                                        ProcessBasicInformation,
                                        &pbi,
                                        size, NULL);
    if (status != ERROR_SUCCESS) {
        return status;
    }

    if (!pbi.PebBaseAddress) {
        /* likely we are 32-bit, pid process is 64-bit */
        return ERROR_DATATYPE_MISMATCH;
    }

    size = sizeof(*peb);

    if (ReadProcessMemory(proc, pbi.PebBaseAddress, peb, size, NULL)) {
        return SIGAR_OK;
    }
    else {
        return GetLastError();
    }
}
Beispiel #7
0
static int tcp_connection_get(sigar_net_connection_walker_t *walker,
                              struct mib2_tcpConnEntry *entry,
                              int len)
{
    int flags = walker->flags;
    int status;
    char *end = (char *)entry + len;

    while ((char *)entry < end) {
        int state = entry->tcpConnEntryInfo.ce_state;

        if (((flags & SIGAR_NETCONN_SERVER) && (state == TCPS_LISTEN)) ||
            ((flags & SIGAR_NETCONN_CLIENT) && (state != TCPS_LISTEN)))
        {
            sigar_net_connection_t conn;

            SIGAR_ZERO(&conn);

            sigar_net_address_set(conn.local_address, entry->tcpConnLocalAddress);
            sigar_net_address_set(conn.remote_address, entry->tcpConnRemAddress);

            conn.local_port = entry->tcpConnLocalPort;
            conn.remote_port = entry->tcpConnRemPort;
            conn.type = SIGAR_NETCONN_TCP;
            conn.send_queue =
                TCPQ_SIZE(entry->tcpConnEntryInfo.ce_snxt -
                          entry->tcpConnEntryInfo.ce_suna - 1);
            conn.receive_queue =
                TCPQ_SIZE(entry->tcpConnEntryInfo.ce_rnxt -
                          entry->tcpConnEntryInfo.ce_rack);

            switch (state) {
              case TCPS_CLOSED:
                conn.state = SIGAR_TCP_CLOSE;
                break;
              case TCPS_IDLE:
                conn.state = SIGAR_TCP_IDLE;
                break;
              case TCPS_BOUND:
                conn.state = SIGAR_TCP_BOUND;
                break;
              case TCPS_LISTEN:
                conn.state = SIGAR_TCP_LISTEN;
                break;
              case TCPS_SYN_SENT:
                conn.state = SIGAR_TCP_SYN_SENT;
                break;
              case TCPS_SYN_RCVD:
                conn.state = SIGAR_TCP_SYN_RECV;
                break;
              case TCPS_ESTABLISHED:
                conn.state = SIGAR_TCP_ESTABLISHED;
                break;
              case TCPS_CLOSE_WAIT:
                conn.state = SIGAR_TCP_CLOSE_WAIT;
                break;
              case TCPS_FIN_WAIT_1:
                conn.state = SIGAR_TCP_FIN_WAIT1;
                break;
              case TCPS_CLOSING:
                conn.state = SIGAR_TCP_CLOSING;
                break;
              case TCPS_LAST_ACK:
                conn.state = SIGAR_TCP_LAST_ACK;
                break;
              case TCPS_FIN_WAIT_2:
                conn.state = SIGAR_TCP_FIN_WAIT2;
                break;
              case TCPS_TIME_WAIT:
                conn.state = SIGAR_TCP_TIME_WAIT;
                break;
              default:
                conn.state = SIGAR_TCP_UNKNOWN;
                break;
            }

            status = walker->add_connection(walker, &conn);
            if (status != SIGAR_OK) {
                return status;
            }
        }

        entry++;
    }

    return SIGAR_OK;
}
Beispiel #8
0
static int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
{
    kstat_ctl_t *kc = sigar->kc;
    kstat_t *ksp;
    uint_t cpuinfo[CPU_STATES];
    unsigned int i;
    int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
    sigar_cache_t *chips;

    if (sigar_kstat_update(sigar) == -1) {
        return errno;
    }

    if (cpulist == &sigar->cpulist) {
        if (sigar->cpulist.size == 0) {
            /* create once */
            sigar_cpu_list_create(cpulist);
        }
        else {
            /* reset, re-using cpulist.data */
            sigar->cpulist.number = 0;
        }
    }
    else {
        sigar_cpu_list_create(cpulist);
    }

    if (is_debug) {
        sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
                         "[cpu_list] OS reports %d CPUs",
                         sigar->ncpu);
    }

    chips = sigar_cache_new(16);
    chips->free_value = free_chip_id;

    for (i=0; i<sigar->ncpu; i++) {
        sigar_cpu_t *cpu;
        char *buf;
        int chip_id;
        sigar_cache_entry_t *ent;

        if (!CPU_ONLINE(sigar->ks.cpuid[i])) {
            sigar_log_printf(sigar, SIGAR_LOG_INFO,
                             "cpu %d (id=%d) is offline",
                             i, sigar->ks.cpuid[i]);
            continue;
        }

        if (!(ksp = sigar->ks.cpu[i])) {
            sigar_log_printf(sigar, SIGAR_LOG_ERROR,
                             "NULL ksp for cpu %d (id=%d)",
                             i, sigar->ks.cpuid[i]);
            continue; /* shouldnot happen */
        }

        if (kstat_read(kc, ksp, NULL) < 0) {
            sigar_log_printf(sigar, SIGAR_LOG_ERROR,
                             "kstat_read failed for cpu %d (id=%d): %s",
                             i, sigar->ks.cpuid[i],
                             sigar_strerror(sigar, errno));
            continue; /* shouldnot happen */
        }

        /*
         * cpu_stat_t is not binary compatible between solaris versions.
         * since cpu_stat is a 'raw' kstat and not 'named' we cannot
         * use name based lookups as we do for others.
         * the start of the cpu_stat_t structure is binary compatible,
         * which looks like so:
         * typedef struct cpu_stat {
         *    kmutex_t        cpu_stat_lock;
         *    cpu_sysinfo_t   cpu_sysinfo;
         *    ...
         *    typedef struct cpu_sysinfo {
         *       ulong cpu[CPU_STATES];
         *       ...
         * we just copy the piece we need below:
         */
        buf = ksp->ks_data;
        buf += sizeof(kmutex_t);
        memcpy(&cpuinfo[0], buf, sizeof(cpuinfo));
        chip_id = sigar->cpu_list_cores ? -1 : get_chip_id(sigar, i);

        if (chip_id == -1) {
            SIGAR_CPU_LIST_GROW(cpulist);
            cpu = &cpulist->data[cpulist->number++];
            SIGAR_ZERO(cpu);
        }
        else {
            /* merge times of logical processors */
            ent = sigar_cache_get(chips, chip_id);
            if (ent->value) {
                cpu = &cpulist->data[(long)ent->value-1];
            }
            else {
                SIGAR_CPU_LIST_GROW(cpulist);
                cpu = &cpulist->data[cpulist->number++];
                ent->value = (void *)(long)cpulist->number;
                SIGAR_ZERO(cpu);

                if (is_debug) {
                    sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
                                     "[cpu_list] Merging times of"
                                     " logical processors for chip_id=%d",
                                     chip_id);
                }
            }
        }

        cpu->user += SIGAR_TICK2MSEC(cpuinfo[CPU_USER]);
        cpu->sys  += SIGAR_TICK2MSEC(cpuinfo[CPU_KERNEL]);
        cpu->idle += SIGAR_TICK2MSEC(cpuinfo[CPU_IDLE]);
        cpu->wait += SIGAR_TICK2MSEC(cpuinfo[CPU_WAIT]);
        cpu->nice += 0; /* no cpu->nice */
        cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait;
    }

    sigar_cache_destroy(chips);

    return SIGAR_OK;
}
Beispiel #9
0
int sigar_net_interface_config_get(sigar_t *sigar, const char *name,
                                   sigar_net_interface_config_t *ifconfig)
{
    int sock;
    struct ifreq ifr;

    if (!name) {
        return sigar_net_interface_config_primary_get(sigar, ifconfig);
    }

    SIGAR_ZERO(ifconfig);

    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        return errno;
    }

    SIGAR_SSTRCPY(ifconfig->name, name);
    SIGAR_SSTRCPY(ifr.ifr_name, name);

#define ifr_s_addr(ifr) \
    ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr

    if (!ioctl(sock, SIOCGIFADDR, &ifr)) {
        sigar_net_address_set(ifconfig->address,
                              ifr_s_addr(ifr));
    }

    if (!ioctl(sock, SIOCGIFNETMASK, &ifr)) {
        sigar_net_address_set(ifconfig->netmask,
                              ifr_s_addr(ifr));
    }

    if (!ioctl(sock, SIOCGIFFLAGS, &ifr)) {
        sigar_uint64_t flags = ifr.ifr_flags;
#ifdef __linux__
# ifndef IFF_DYNAMIC
#  define IFF_DYNAMIC 0x8000 /* not in 2.2 kernel */
# endif /* IFF_DYNAMIC */
        int is_mcast = flags & IFF_MULTICAST;
        int is_slave = flags & IFF_SLAVE;
        int is_master = flags & IFF_MASTER;
        int is_dynamic = flags & IFF_DYNAMIC;
        /*
         * XXX: should just define SIGAR_IFF_*
         * and test IFF_* bits on given platform.
         * this is the only diff between solaris/hpux/linux
         * for the flags we care about.
         *
         */
        flags &= ~(IFF_MULTICAST|IFF_SLAVE|IFF_MASTER);
        if (is_mcast) {
            flags |= SIGAR_IFF_MULTICAST;
        }
        if (is_slave) {
            flags |= SIGAR_IFF_SLAVE;
        }
        if (is_master) {
            flags |= SIGAR_IFF_MASTER;
        }
        if (is_dynamic) {
            flags |= SIGAR_IFF_DYNAMIC;
        }
#endif
        ifconfig->flags = flags;
    }
    else {
        /* should always be able to get flags for existing device */
        /* other ioctls may fail if device is not enabled: ok */
        close(sock);
        return errno;
    }

    if (ifconfig->flags & IFF_LOOPBACK) {
        sigar_net_address_set(ifconfig->destination,
                              ifconfig->address.addr.in);
        sigar_net_address_set(ifconfig->broadcast, 0);
        sigar_hwaddr_set_null(ifconfig);
        SIGAR_SSTRCPY(ifconfig->type,
                      SIGAR_NIC_LOOPBACK);
    }
    else {
        if (!ioctl(sock, SIOCGIFDSTADDR, &ifr)) {
            sigar_net_address_set(ifconfig->destination,
                                  ifr_s_addr(ifr));
        }

        if (!ioctl(sock, SIOCGIFBRDADDR, &ifr)) {
            sigar_net_address_set(ifconfig->broadcast,
                                  ifr_s_addr(ifr));
        }

#if defined(HAVE_LIBDLPI_H)
        hwaddr_libdlpi_lookup(sigar, ifconfig);
#elif defined(SIOCGIFHWADDR)
        if (!ioctl(sock, SIOCGIFHWADDR, &ifr)) {
            get_interface_type(ifconfig,
                               ifr.ifr_hwaddr.sa_family);
            sigar_net_address_mac_set(ifconfig->hwaddr,
                                      ifr.ifr_hwaddr.sa_data,
                                      IFHWADDRLEN);
        }
#elif defined(_AIX) || defined(__osf__)
        hwaddr_aix_lookup(sigar, ifconfig);
        SIGAR_SSTRCPY(ifconfig->type,
                      SIGAR_NIC_ETHERNET);
#else
        hwaddr_arp_lookup(ifconfig, sock);
        SIGAR_SSTRCPY(ifconfig->type,
                      SIGAR_NIC_ETHERNET);
#endif
    }

#if defined(SIOCGLIFMTU) && !defined(__hpux)
    {
        struct lifreq lifr;
        SIGAR_SSTRCPY(lifr.lifr_name, name);
        if(!ioctl(sock, SIOCGLIFMTU, &lifr)) {
            ifconfig->mtu = lifr.lifr_mtu;
        }
    }
#elif defined(SIOCGIFMTU)
    if (!ioctl(sock, SIOCGIFMTU, &ifr)) {
#  if defined(__hpux)
        ifconfig->mtu = ifr.ifr_metric;
#  else
        ifconfig->mtu = ifr.ifr_mtu;
#endif
    }
#else
    ifconfig->mtu = 0; /*XXX*/
#endif

    if (!ioctl(sock, SIOCGIFMETRIC, &ifr)) {
        ifconfig->metric = ifr.ifr_metric ? ifr.ifr_metric : 1;
    }

#if defined(SIOCGIFTXQLEN)
    if (!ioctl(sock, SIOCGIFTXQLEN, &ifr)) {
        ifconfig->tx_queue_len = ifr.ifr_qlen;
    }
    else {
        ifconfig->tx_queue_len = -1; /* net-tools behaviour */
    }
#else
    ifconfig->tx_queue_len = -1;
#endif

    close(sock);

    /* XXX can we get a better description like win32? */
    SIGAR_SSTRCPY(ifconfig->description,
                  ifconfig->name);

    sigar_net_interface_ipv6_config_init(ifconfig);
    sigar_net_interface_ipv6_config_get(sigar, name, ifconfig);

    return SIGAR_OK;
}
Beispiel #10
0
static int net_conn_get_tcp(sigar_net_connection_walker_t *walker)
{
    sigar_t *sigar = walker->sigar;
    int flags = walker->flags;
    int status, count, i;
    unsigned int len;
    mib_tcpConnEnt *entries;
    struct nmparms parms;

    len = sizeof(count);
    parms.objid = ID_tcpConnNumEnt;
    parms.buffer = &count;
    parms.len = &len;

    if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
        return status;
    }

    if (count <= 0) {
        return ENOENT;
    }

    len =  count * sizeof(*entries);
    entries = malloc(len);
    parms.objid = ID_tcpConnTable;
    parms.buffer = entries;
    parms.len = &len;

    if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
        free(entries);
        return status;
    }

    for (i=0; i<count; i++) {
        sigar_net_connection_t conn;
        mib_tcpConnEnt *entry = &entries[i];
        int state = entry->State;

        if (!(IS_TCP_SERVER(state, flags) ||
              IS_TCP_CLIENT(state, flags)))
        {
            continue;
        }

        SIGAR_ZERO(&conn);

        switch (state) {
          case TCCLOSED:
            conn.state = SIGAR_TCP_CLOSE;
            break;
          case TCLISTEN:
            conn.state = SIGAR_TCP_LISTEN;
            break;
          case TCSYNSENT:
            conn.state = SIGAR_TCP_SYN_SENT;
            break;
          case TCSYNRECEIVE:
            conn.state = SIGAR_TCP_SYN_RECV;
            break;
          case TCESTABLISED:
            conn.state = SIGAR_TCP_ESTABLISHED;
            break;
          case TCFINWAIT1:
            conn.state = SIGAR_TCP_FIN_WAIT1;
            break;
          case TCFINWAIT2:
            conn.state = SIGAR_TCP_FIN_WAIT2;
            break;
          case TCCLOSEWAIT:
            conn.state = SIGAR_TCP_CLOSE_WAIT;
            break;
          case TCCLOSING:
            conn.state = SIGAR_TCP_CLOSING;
            break;
          case TCLASTACK:
            conn.state = SIGAR_TCP_LAST_ACK;
            break;
          case TCTIMEWAIT:
            conn.state = SIGAR_TCP_TIME_WAIT;
            break;
          case TCDELETETCB:
          default:
            conn.state = SIGAR_TCP_UNKNOWN;
            break;
        }

        conn.local_port  = (unsigned short)entry->LocalPort;
        conn.remote_port = (unsigned short)entry->RemPort;
        conn.type = SIGAR_NETCONN_TCP;

        sigar_net_address_set(conn.local_address, entry->LocalAddress);
        sigar_net_address_set(conn.remote_address, entry->RemAddress);

        conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;

        if (walker->add_connection(walker, &conn) != SIGAR_OK) {
            break;
        }
    }

    free(entries);

    return SIGAR_OK;
}
Beispiel #11
0
int sigar_net_route_list_get(sigar_t *sigar,
                             sigar_net_route_list_t *routelist)
{
    int status, count, i;
    unsigned int len;
    struct nmparms parms;
    mib_ipRouteEnt *routes;
    sigar_net_route_t *route;

    len = sizeof(count);
    parms.objid = ID_ipRouteNumEnt;
    parms.buffer = &count;
    parms.len = &len;

    if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
        return status;
    }

    len = count * sizeof(*routes);
    routes = malloc(len);

    parms.objid = ID_ipRouteTable;
    parms.buffer = routes;
    parms.len = &len;

    if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
        free(routes);
        return status;
    }

    routelist->size = routelist->number = 0;

    sigar_net_route_list_create(routelist);

    for (i=0; i<count; i++) {
        mib_ipRouteEnt *ent = &routes[i];

        SIGAR_NET_ROUTE_LIST_GROW(routelist);

        route = &routelist->data[routelist->number++];
        SIGAR_ZERO(route); /* XXX: other fields */
        
        sigar_net_address_set(route->destination,
                              ent->Dest);

        sigar_net_address_set(route->mask,
                              ent->Mask);

        sigar_net_address_set(route->gateway,
                              ent->NextHop);

        route->flags = SIGAR_RTF_UP;
        if ((ent->Dest == 0) &&
            (ent->Mask == 0))
        {
            route->flags |= SIGAR_RTF_GATEWAY;
        }
    }

    free(routes);
    
    return SIGAR_OK;
}