Index: sys/net/if.h =================================================================== --- sys/net/if.h +++ sys/net/if.h @@ -68,6 +68,35 @@ char *ifcr_buffer; /* buffer for cloner names */ }; +struct xifrstat { + uint64_t ifrs_ifinput; + uint64_t ifrs_netisr; + uint64_t ifrs_ether; + uint64_t ifrs_ip; + uint64_t ifrs_ip6; + uint64_t ifrs_udp; + uint64_t ifrs_tcp; +}; + +struct if_ring_data { + /* Unions are here to make sizes MI. */ + union { /* uptime at attach or stat reset */ + time_t ifrd_epoch; + uint64_t __ifrd_epoch_ph; + }; + union { /* time of last administrative change */ + struct timeval ifrd_lastchange; + struct { + uint64_t ph1; + uint64_t ph2; + } __ifrd_lastchange_ph; + }; + + int ifrd_ncpus; + int ifrd_nrings; + struct xifrstat ifrd_stats[0]; +}; + /* * Structure describing information about an interface * which may be of interest to management entities. Index: sys/net/if.c =================================================================== --- sys/net/if.c +++ sys/net/if.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -1770,6 +1771,39 @@ } /* + * Copy data from ifring to userland API structure if_ring_data. + */ +void +if_ring_data_copy(struct ifnet *ifp, struct if_ring_data *ifrd) +{ + struct ifrstat *ifrs; + struct xifrstat *xifrs; + int ri, cpu; + + ifrd->ifrd_epoch = ifp->if_epoch; + ifrd->ifrd_lastchange = ifp->if_lastchange; + + ifrd->ifrd_ncpus = mp_ncpus; + ifrd->ifrd_nrings = ifp->if_nrings; + + for (ri = 0; ri < ifp->if_nrings; ri++) { + for (cpu = 0; cpu < mp_ncpus; cpu++) { + + ifrs = &ifp->if_rings[ri]->ifr_stats[cpu]; + xifrs = &ifrd->ifrd_stats[ri * mp_ncpus + cpu]; + + xifrs->ifrs_ifinput = ifrs->ifrs_ifinput; + xifrs->ifrs_netisr = ifrs->ifrs_netisr; + xifrs->ifrs_ether = ifrs->ifrs_ether; + xifrs->ifrs_ip = ifrs->ifrs_ip; + xifrs->ifrs_ip6 = ifrs->ifrs_ip6; + xifrs->ifrs_udp = ifrs->ifrs_udp; + xifrs->ifrs_tcp = ifrs->ifrs_tcp; + } + } +} + +/* * Initialization, destruction and refcounting functions for ifaddrs. */ struct ifaddr * Index: sys/net/if_mib.h =================================================================== --- sys/net/if_mib.h +++ sys/net/if_mib.h @@ -40,9 +40,16 @@ int ifmd_snd_maxlen; /* maximum length of send queue */ int ifmd_snd_drops; /* number of drops in send queue */ int ifmd_filler[4]; /* for future expansion */ - struct if_data ifmd_data; /* generic information and statistics */ + union { + struct if_data ifmd_data; /* generic information and statistics */ + struct if_ring_data ifmd_ring_data; + }; }; +#ifdef CTASSERT +CTASSERT(sizeof(struct if_data) >= sizeof(struct if_ring_data)); +#endif + /* * sysctl MIB tags at the net.link.generic level */ @@ -55,6 +62,7 @@ #define IFDATA_GENERAL 1 /* generic stats for all kinds of ifaces */ #define IFDATA_LINKSPECIFIC 2 /* specific to the type of interface */ #define IFDATA_DRIVERNAME 3 /* driver name and unit */ +#define IFDATA_RINGINFO 4 /* ring statistics */ /* * MIB tags at the net.link.generic.system level Index: sys/net/if_mib.c =================================================================== --- sys/net/if_mib.c +++ sys/net/if_mib.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,8 @@ * - a link-type-specific data * structure (as might be used * by an SNMP agent + * .ifdata..ringinfo + * - what's in `struct if_ring_data' * * Perhaps someday we will make addresses accessible via this interface * as well (then there will be four such...). The reason that the @@ -78,7 +81,7 @@ int error; u_int namelen = arg2; struct ifnet *ifp; - struct ifmibdata ifmd; + struct ifmibdata *ifmd = NULL; size_t dlen; char *dbuf; @@ -96,18 +99,23 @@ goto out; case IFDATA_GENERAL: - bzero(&ifmd, sizeof(ifmd)); - strlcpy(ifmd.ifmd_name, ifp->if_xname, sizeof(ifmd.ifmd_name)); + ifmd = malloc(sizeof(*ifmd), M_TEMP, M_NOWAIT | M_ZERO); + if (ifmd == NULL) { + error = ENOMEM; + goto out; + } + strlcpy(ifmd->ifmd_name, ifp->if_xname, + sizeof(ifmd->ifmd_name)); - ifmd.ifmd_pcount = ifp->if_pcount; - if_data_copy(ifp, &ifmd.ifmd_data); + ifmd->ifmd_pcount = ifp->if_pcount; + if_data_copy(ifp, &ifmd->ifmd_data); - ifmd.ifmd_flags = ifp->if_flags; - ifmd.ifmd_snd_len = 0; /* XXXGL */ - ifmd.ifmd_snd_maxlen = 0; /* XXXGL */ - ifmd.ifmd_snd_drops = if_get_counter(ifp, IFCOUNTER_OQDROPS); + ifmd->ifmd_flags = ifp->if_flags; + ifmd->ifmd_snd_len = 0; /* XXXGL */ + ifmd->ifmd_snd_maxlen = 0; /* XXXGL */ + ifmd->ifmd_snd_drops = if_get_counter(ifp, IFCOUNTER_OQDROPS); - error = SYSCTL_OUT(req, &ifmd, sizeof ifmd); + error = SYSCTL_OUT(req, ifmd, sizeof(*ifmd)); if (error) goto out; break; @@ -140,8 +148,28 @@ error = EPERM; free(dbuf, M_TEMP); goto out; + + case IFDATA_RINGINFO: + dlen = sizeof(*ifmd) + sizeof(struct xifrstat) * mp_ncpus * + ifp->if_nrings; + + ifmd = malloc(dlen, M_TEMP, M_NOWAIT | M_ZERO); + if (ifmd == NULL) { + error = ENOMEM; + goto out; + } + strlcpy(ifmd->ifmd_name, ifp->if_xname, + sizeof(ifmd->ifmd_name)); + if_ring_data_copy(ifp, &ifmd->ifmd_ring_data); + + error = SYSCTL_OUT(req, ifmd, dlen); + if (error) + goto out; + break; } out: + if (ifmd != NULL) + free(ifmd, M_TEMP); if_rele(ifp); return error; } Index: sys/net/if_var.h =================================================================== --- sys/net/if_var.h +++ sys/net/if_var.h @@ -450,6 +450,7 @@ int if_simloop(struct ifnet *ifp, struct mbuf *m, int af, int hlen); void if_data_copy(struct ifnet *, struct if_data *); +void if_ring_data_copy(struct ifnet *, struct if_ring_data *); int if_getmtu_family(if_t ifp, int family); int if_setupmultiaddr(if_t ifp, void *mta, int *cnt, int max);