Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 19 Aug 2009 03:11:27 GMT
From:      Gabor Pali <pgj@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 167493 for review
Message-ID:  <200908190311.n7J3BRLl066587@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=167493

Change 167493 by pgj@petymeg-current on 2009/08/19 03:10:40

	- Add mroute_type for representing multicast forwarding table
	  entries.
	- Add netstat_mroute(), a function for collecting multicast forwarding
	  information.
	- Add code for both PF_INET and PF_INET6.  Note that bandwidth meters
	  are not included yet.

Affected files ...

.. //depot/projects/soc2009/pgj_libstat/src/lib/libnetstat/netstat.h#64 edit
.. //depot/projects/soc2009/pgj_libstat/src/lib/libnetstat/netstat_internal.h#60 edit
.. //depot/projects/soc2009/pgj_libstat/src/lib/libnetstat/netstat_mroute.c#2 edit
.. //depot/projects/soc2009/pgj_libstat/src/lib/libnetstat/netstat_util.c#69 edit

Differences ...

==== //depot/projects/soc2009/pgj_libstat/src/lib/libnetstat/netstat.h#64 (text+ko) ====

@@ -50,6 +50,7 @@
 
 #define BPFTYPE_MAXNAME		    IFNAMSIZ
 #define MIFTYPE_MAXNAME		    IFNAMSIZ
+#define MRTTYPE_MAXVIFS		    MAXVIFS
 
 #define NETSTAT_ERROR_UNDEFINED	    0
 #define NETSTAT_ERROR_NOMEMORY	    1
@@ -131,6 +132,8 @@
 #define NETSTAT_MIF_SRCRT	0x02
 #define NETSTAT_MIF_REGISTER	0x04
 
+#define	NETSTAT_MROUTE_INCOMPLETE_PARENT	MF6C_INCOMPLETE_PARENT
+
 /* Enum for TCP states: */
 enum tcp_state {
     tcps_Closed,
@@ -278,6 +281,10 @@
 struct mcastif_type_list;
 struct mcastif_type_iterator;
 
+struct mroute_type;
+struct mroute_type_list;
+struct mroute_type_iterator;
+
 __BEGIN_DECLS
 const char		    *netstat_strerror(int);
 const char		    *netstat_kvmerror(const struct session_type *);
@@ -1303,4 +1310,29 @@
 u_int64_t   netstat_mit_get_bytes_in(const struct mcastif_type *);
 u_int64_t   netstat_mit_get_bytes_out(const struct mcastif_type *);
 const char  *netstat_mit_get_ifname(const struct mcastif_type *);
+
+
+/* Multicast routing: */
+struct mroute_type_list	*netstat_mrtl_alloc(void);
+void	netstat_mrtl_free(struct mroute_type_list *);
+int	netstat_mrtl_geterror(const struct mroute_type_list *);
+int	netstat_mrtl_length(const struct mroute_type_list *);
+
+int	netstat_mrti_alloc(struct mroute_type_list *list,
+	    struct mroute_type_iterator **iterator);
+const struct mroute_type *netstat_mrti_first(struct mroute_type_iterator *);
+const struct mroute_type *netstat_mrti_next(struct mroute_type_iterator *);
+void	netstat_mrti_free(struct mroute_type_iterator *);
+
+int netstat_mroute(const struct session_type *, int domain,
+    struct mroute_type_list *list, int flags);
+
+const struct routeaddr_type *netstat_mrt_get_origin(const struct mroute_type *);
+const struct routeaddr_type *netstat_mrt_get_group(const struct mroute_type *);
+u_int64_t   netstat_mrt_get_packets(const struct mroute_type *);
+u_int64_t   netstat_mrt_get_bytes(const struct mroute_type *);
+u_int64_t   netstat_mrt_get_waitings(const struct mroute_type *);
+u_int32_t   netstat_mrt_get_parent(const struct mroute_type *);
+u_int8_t    netstat_mrt_get_ttl(const struct mroute_type *, int);
+int	    netstat_mrt_get_is_mif_set(const struct mroute_type *, u_int32_t);
 #endif /* !_NETSTAT_H_ */

==== //depot/projects/soc2009/pgj_libstat/src/lib/libnetstat/netstat_internal.h#60 (text+ko) ====

@@ -528,6 +528,34 @@
 	struct mcastif_type	    *miti_next;
 };
 
+
+/* Multicast route type. */
+struct mroute_type {
+	struct routeaddr_type	    *mrt_origin;
+	struct routeaddr_type	    *mrt_group;
+	u_int64_t		    mrt_pkt_cnt;
+	u_int64_t		    mrt_byte_cnt;
+	u_int64_t		    mrt_nstall;
+	u_int32_t		    mrt_parent;
+	u_int8_t		    mrt_ttls[MRTTYPE_MAXVIFS];
+	struct if_set		    mrt_ifset;
+
+	TAILQ_ENTRY(mroute_type)    mrt_list;
+};
+
+struct mroute_type_list {
+	TAILQ_HEAD(, mroute_type)   mrtl_list;
+	int			    mrtl_length;
+	int			    mrtl_error;
+};
+
+struct mroute_type_iterator {
+	struct mroute_type_list	*mrti_list;
+	struct mroute_type	*mrti_first;
+	struct mroute_type	*mrti_next;
+};
+
+
 int kread_data(kvm_t *kvm, u_long kvm_pointer, void *address, size_t size);
 int kread_string(kvm_t *kvm, u_long kvm_pointer, char *buffer, int buflen);
 
@@ -563,6 +591,13 @@
 void _netstat_mit_free(struct mcastif_type *);
 struct mcastif_type *_netstat_mit_allocate(struct mcastif_type_list *);
 
+void _netstat_mrtl_empty(struct mroute_type_list *);
+void _netstat_mrt_free(struct mroute_type *);
+struct mroute_type *_netstat_mrt_allocate(struct mroute_type_list *);
+#ifdef INET6
+int _mrt6_get_nstall_kvm(kvm_t *, struct mf6c *);
+#endif /* !INET6 */
+
 struct routeaddr_type *extract_address(void *, void *, int);
 const char  *resolve_val2str_name(int, const struct val2str *);
 /* XXX: merge these into a common address resolution routine. */

==== //depot/projects/soc2009/pgj_libstat/src/lib/libnetstat/netstat_mroute.c#2 (text+ko) ====

@@ -63,6 +63,15 @@
 static const char *const mif_symbol[] =
     { "_viftable" };
 
+enum nlMRT {
+	nlMRT_mfchashtbl = 0,
+	nlMRT_mfctablesize,
+	nlMRT_MAX,
+};
+
+static const char *const mrt_symbol[] =
+    { "_mfchashtbl", "_mfctablesize" };
+
 #ifdef INET6
 enum nlMIF6 {
 	nlMIF6_mif6table = 0,
@@ -71,20 +80,36 @@
 
 static const char *const mif6_symbol[] =
     { "_mif6table" };
+
+enum nlMRT6 {
+	nlMRT6_mf6ctable = 0,
+	nlMRT6_MAX,
+};
+
+static const char *const mrt6_symbol[] =
+    { "_mf6ctable" };
 #endif /* !INET6 */
 
 static int mif_kvm(struct mcastif_type_list *, kvm_t *, struct nlist *);
 static int mif_sysctl(struct mcastif_type_list *);
+static int mrt_kvm(struct mroute_type_list *, kvm_t *, struct nlist *);
+static int mrt_sysctl(struct mroute_type_list *);
 #ifdef INET6
 static int mif6_kvm(struct mcastif_type_list *, kvm_t *, struct nlist *);
 static int mif6_sysctl(struct mcastif_type_list *);
+static int mrt6_kvm(struct mroute_type_list *, kvm_t *, struct nlist *);
+static int mrt6_sysctl(struct mroute_type_list *);
 #endif /* !INET6 */
 
 static void extract_vif_data(int, struct vif *, struct mcastif_type *);
 static void extract_svif_data(int, struct vif_data *, struct mcastif_type *);
+static void extract_mfc_data(struct mfc *, struct mroute_type *);
+static void extract_smfc_data(struct mfc_data *, struct mroute_type *);
 #ifdef INET6
 static void extract_mif6_data(int, struct mif6 *, struct mcastif_type *);
 static void extract_smif6_data(int, struct mif6_data *, struct mcastif_type *);
+static void extract_mf6c_data(int, struct mf6c *, struct mroute_type *);
+static void extract_smf6c_data(struct mf6c_data *, struct mroute_type *);
 #endif /* !INET6 */
 
 #ifdef INET6
@@ -165,6 +190,7 @@
 		free(nls[i].n_name);
 	return (result);
 }
+#undef nls_size
 
 int
 mif_kvm(struct mcastif_type_list *list, kvm_t *kvm, struct nlist *nlp)
@@ -474,5 +500,341 @@
 }
 
 #undef CNV_FLAG
+#endif /* !INET6 */
+
+
+#ifdef INET6
+#define nls_size    (nlMRT_MAX + nlMRT6_MAX + 1)
+#else
+#define	nls_size    (nlMRT_MAX + 1)
+#endif /* !INET6 */
+
+int
+netstat_mroute(const struct session_type *session, int domain,
+    struct mroute_type_list *list, __unused int flags)
+{
+	int result, use_kvm, i;
+	struct nlist nls[nls_size];
+
+	result = -1;
+	use_kvm = session->sst_flags & NETSTAT_SESSION_KVM;
+	bzero(nls, sizeof(nls));
+
+	if (use_kvm) {
+		switch (domain) {
+		case PF_UNSPEC:
+			for (i = 0; i < nlMRT_MAX; i++)
+				nls[i].n_name = strdup(mrt_symbol[i]);
+			for (i = nlMRT_MAX; i < nls_size; i++)
+				nls[i].n_name =
+				    strdup(mrt6_symbol[i - nlMRT_MAX]);
+			break;
+		case PF_INET:
+			for (i = 0; i < nlMRT_MAX; i++)
+				nls[i].n_name = strdup(mrt_symbol[i]);
+			break;
+#ifdef INET6
+		case PF_INET6:
+			for (i = 0; i < nlMRT6_MAX; i++)
+				nls[i].n_name = strdup(mrt6_symbol[i]);
+			break;
+#endif /* !INET6 */
+		default:
+			break;
+		}
+		if (kvm_nlist(session->sst_kvm, nls) < 0) {
+			list->mrtl_error = NETSTAT_ERROR_KVM;
+			goto end;
+		}
+	}
+
+	switch (domain) {
+	case PF_UNSPEC:
+		result = use_kvm ?
+		    mrt_kvm(list, session->sst_kvm, nls) :
+		    mrt_sysctl(list);
+		if (result < 0)
+			goto end;
+		result = use_kvm ?
+		    mrt6_kvm(list, session->sst_kvm, &nls[nlMRT_MAX]) :
+		    mrt6_sysctl(list);
+		break;
+	case PF_INET:
+		result = use_kvm ?
+		    mrt_kvm(list, session->sst_kvm, nls) :
+		    mrt_sysctl(list);
+		break;
+#ifdef INET6
+	case PF_INET6:
+		result = use_kvm ?
+		    mrt6_kvm(list, session->sst_kvm, nls) :
+		    mrt6_sysctl(list);
+		break;
+#endif /* !INET6 */
+	default:
+		list->mrtl_error = NETSTAT_ERROR_UNSUPPORTED;
+		break;
+	}
+
+end:
+	for (i = 0; nls[i].n_name != NULL && i < nls_size; i++)
+		free(nls[i].n_name);
+	return (result);
+}
+#undef nls_size
+
+int
+mrt_kvm(struct mroute_type_list *list, kvm_t *kvm, struct nlist *nlp)
+{
+	u_long mfctablesize, i;
+	LIST_HEAD(, mfc) *mfchashtbl;
+	struct mfc mfc, *m;
+	struct mroute_type *mrtp;
+	size_t len;
+
+	if (kread_data(kvm, (uintptr_t)nlp[nlMRT_mfctablesize].n_value,
+	    &mfctablesize, sizeof(mfctablesize)) != 0) {
+		list->mrtl_error = NETSTAT_ERROR_KVM;
+		return (-1);
+	}
+
+	len = sizeof(*mfchashtbl) * mfctablesize;
+	mfchashtbl = malloc(len);
+	if (mfchashtbl == NULL) {
+		list->mrtl_error = NETSTAT_ERROR_NOMEMORY;
+		return (-1);
+	}
+
+	if (kread_data(kvm, (uintptr_t)nlp[nlMRT_mfchashtbl].n_value,
+	    mfchashtbl, len) != 0) {
+		list->mrtl_error = NETSTAT_ERROR_KVM;
+		return (-1);
+	}
+
+	for (i = 0; i < mfctablesize; i++) {
+		LIST_FOREACH(m, &mfchashtbl[i], mfc_hash) {
+			if (kread_data(kvm, (uintptr_t)m, &mfc,
+			    sizeof(mfc)) != 0)
+				continue;
+			mrtp = _netstat_mrt_allocate(list);
+			extract_mfc_data(&mfc, mrtp);
+		}
+	}
+
+	free(mfchashtbl);
+	return (0);
+}
+
+int
+mrt_sysctl(struct mroute_type_list *list)
+{
+	const char *mibvar = "net.inet.ip.smfctable";
+
+	struct mfc_stream *msp;
+	struct mfc_data *mdp;
+	struct mroute_type *mrtp;
+	char *buf, *p;
+	size_t len;
+	int result;
+	u_int32_t i;
+
+	result = -1;
+	len = 0;
+	if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+		if (errno != ENOENT)
+			warn("sysctl: %s", mibvar);
+		goto out2;
+	}
+	if ((buf = malloc(len)) == 0) {
+		warnx("malloc %lu bytes", (u_long)len);
+		goto out2;
+	}
+	if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+		warn("sysctl: %s", mibvar);
+		goto out1;
+	}
+	if (len < sizeof(*msp)) {
+		list->mrtl_error = NETSTAT_ERROR_VERSION;
+		goto out1;
+	}
+
+	p = buf;
+	msp = (struct mfc_stream *)p;
+	p+= sizeof(*msp);
+
+	if (msp->ms_version != MFC_STREAM_VERSION) {
+		list->mrtl_error = NETSTAT_ERROR_VERSION;
+		goto out1;
+	}
+
+	for (i = 0; i < msp->ms_count; i++) {
+		mdp = (struct mfc_data *)p;
+		p += sizeof(*mdp);
+		mrtp = _netstat_mrt_allocate(list);
+		extract_smfc_data(mdp, mrtp);
+	}
+
+	result = 0;
+
+out1:	free(buf);
+out2:	return (result);
+}
+
+#ifdef INET6
+int
+mrt6_kvm(struct mroute_type_list *list, kvm_t *kvm, struct nlist *nlp)
+{
+	struct mf6c *mf6ctable[MF6CTBLSIZ], *mfcp;
+	struct mf6c mfc;
+	struct mroute_type *mrtp;
+	int i;
 
+	if (kread_data(kvm, (uintptr_t)nlp[nlMRT6_mf6ctable].n_value,
+	    mf6ctable, sizeof(mf6ctable)) != 0) {
+		list->mrtl_error = NETSTAT_ERROR_KVM;
+		return (-1);
+	}
+
+	for (i = 0; i < MF6CTBLSIZ; ++i) {
+		for (mfcp = mf6ctable[i]; mfcp != NULL; mfcp = mfc.mf6c_next) {
+			kread_data(kvm, (uintptr_t)mfcp, &mfc, sizeof(mfc));
+			mrtp = _netstat_mrt_allocate(list);
+			extract_mf6c_data(_mrt6_get_nstall_kvm(kvm, &mfc),
+			    &mfc, mrtp);
+		}
+	}
+
+	return (0);
+}
+
+int
+mrt6_sysctl(struct mroute_type_list *list)
+{
+	const char *mibvar = "net.inet6.ip6.smf6ctable";
+
+	struct mf6c_stream *msp;
+	struct mf6c_data *mdp;
+	struct mroute_type *mrtp;
+	char *buf, *p;
+	size_t len;
+	int result;
+	u_int32_t i;
+
+	result = -1;
+	len = 0;
+	if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+		if (errno != ENOENT)
+			warn("sysctl: %s", mibvar);
+		goto out2;
+	}
+	if ((buf = malloc(len)) == 0) {
+		warnx("malloc %lu bytes", (u_long)len);
+		goto out2;
+	}
+	if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+		warn("sysctl: %s", mibvar);
+		goto out1;
+	}
+	if (len < sizeof(*msp)) {
+		list->mrtl_error = NETSTAT_ERROR_VERSION;
+		goto out1;
+	}
+
+	p = buf;
+	msp = (struct mf6c_stream *)p;
+	p+= sizeof(*msp);
+
+	if (msp->ms_version != MF6C_STREAM_VERSION) {
+		list->mrtl_error = NETSTAT_ERROR_VERSION;
+		goto out1;
+	}
+
+	for (i = 0; i < msp->ms_count; i++) {
+		mdp = (struct mf6c_data *)p;
+		p += sizeof(*mdp);
+		mrtp = _netstat_mrt_allocate(list);
+		extract_smf6c_data(mdp, mrtp);
+	}
+
+	result = 0;
+
+out1:	free(buf);
+out2:	return (result);
+}
+#endif /* !INET6 */
+
+void
+extract_mfc_data(struct mfc *m, struct mroute_type *mrtp)
+{
+	int i;
+	struct sockaddr_in sa_in;
+
+	bzero(&sa_in, sizeof(struct sockaddr_in));
+	sa_in.sin_len = sizeof(struct sockaddr_in);
+	sa_in.sin_family = PF_INET;
+	sa_in.sin_addr = m->mfc_origin;
+
+	mrtp->mrt_origin = extract_address(&sa_in, NULL, 0);
+	sa_in.sin_addr = m->mfc_mcastgrp;
+	mrtp->mrt_group = extract_address(&sa_in, NULL, 0);
+	mrtp->mrt_pkt_cnt = m->mfc_pkt_cnt;
+	mrtp->mrt_byte_cnt = m->mfc_byte_cnt;
+	mrtp->mrt_nstall = m->mfc_nstall;
+	mrtp->mrt_parent = m->mfc_parent;
+	for (i = 0; i < MAXVIFS; i++)
+		mrtp->mrt_ttls[i] = m->mfc_ttls[i];
+}
+
+void
+extract_smfc_data(struct mfc_data *md, struct mroute_type *mrtp)
+{
+	struct sockaddr_in sa_in;
+
+	bzero(&sa_in, sizeof(struct sockaddr_in));
+	sa_in.sin_len = sizeof(struct sockaddr_in);
+	sa_in.sin_family = PF_INET;
+	sa_in.sin_addr.s_addr = md->md_origin;
+
+	mrtp->mrt_origin = extract_address(&sa_in, NULL, 0);
+	sa_in.sin_addr.s_addr = md->md_mcastgrp;
+	mrtp->mrt_group = extract_address(&sa_in, NULL, 0);
+	mrtp->mrt_pkt_cnt = md->md_pkt_cnt;
+	mrtp->mrt_byte_cnt = md->md_byte_cnt;
+	mrtp->mrt_nstall = md->md_nstall;
+	mrtp->mrt_parent = md->md_parent;
+	bcopy(md->md_ttls, mrtp->mrt_ttls, sizeof(md->md_ttls));
+}
+
+#ifdef INET6
+void
+extract_mf6c_data(int nstall, struct mf6c *m, struct mroute_type *mrtp)
+{
+	mrtp->mrt_origin = extract_address(&m->mf6c_origin, NULL, 0);
+	mrtp->mrt_group = extract_address(&m->mf6c_mcastgrp, NULL, 0);
+	mrtp->mrt_pkt_cnt = m->mf6c_pkt_cnt;
+	mrtp->mrt_byte_cnt = m->mf6c_byte_cnt;
+	mrtp->mrt_nstall = nstall;
+	mrtp->mrt_parent = m->mf6c_parent;
+	mrtp->mrt_ifset = m->mf6c_ifset;
+}
+
+void
+extract_smf6c_data(struct mf6c_data *md, struct mroute_type *mrtp)
+{
+	struct sockaddr_in6 sa_in6;
+
+	bzero(&sa_in6, sizeof(struct sockaddr_in6));
+	sa_in6.sin6_len = sizeof(struct sockaddr_in6);
+	sa_in6.sin6_family = PF_INET6;
+	sa_in6.sin6_addr = *((struct in6_addr *)md->md_origin);
+
+	mrtp->mrt_origin = extract_address(&sa_in6, NULL, 0);
+	sa_in6.sin6_addr = *((struct in6_addr *)md->md_mcastgrp);
+	mrtp->mrt_group = extract_address(&sa_in6, NULL, 0);
+	mrtp->mrt_pkt_cnt = md->md_pkt_cnt;
+	mrtp->mrt_byte_cnt = md->md_byte_cnt;
+	mrtp->mrt_nstall = md->md_nstall;
+	mrtp->mrt_parent = md->md_parent;
+	bcopy(&md->md_ifs_bits, &mrtp->mrt_ifset, sizeof(md->md_ifs_bits));
+}
 #endif /* !INET6 */

==== //depot/projects/soc2009/pgj_libstat/src/lib/libnetstat/netstat_util.c#69 (text+ko) ====

@@ -31,11 +31,18 @@
 #include <sys/types.h>
 #include <sys/protosw.h>
 #include <sys/domain.h>
+#include <sys/param.h>
 
 #include <net/pfkeyv2.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+#ifdef INET6
+#define _KERNEL
+#include <netinet6/ip6_mroute.h>
+#undef _KERNEL
+#endif /* !INET6 */
+
 #include <kvm.h>
 #include <libutil.h>
 #include <netdb.h>
@@ -130,6 +137,23 @@
 	return (0);
 }
 
+#ifdef INET6
+int
+_mrt6_get_nstall_kvm(kvm_t *kvm, struct mf6c *m)
+{
+	int result;
+	struct rtdetq rte, *rtep;
+
+	result = 0;
+	for (rtep = m->mf6c_stall; rtep != NULL; rtep = rte.next) {
+		kread_data(kvm, (uintptr_t)rtep, &rte, sizeof(rte));  
+		result++;
+	}
+
+	return (result);
+}
+#endif /* !INET6 */
+
 const char *
 netstat_strerror(int error)
 {
@@ -2739,6 +2763,172 @@
 }
 
 
+void
+_netstat_mrtl_empty(struct mroute_type_list *list)
+{
+	struct mroute_type *mrtp;
+
+	while ((mrtp = TAILQ_FIRST(&list->mrtl_list)) ) {
+		TAILQ_REMOVE(&list->mrtl_list, mrtp, mrt_list);
+		_netstat_mrt_free(mrtp);
+	}
+
+	list->mrtl_length = 0;
+}
+
+void
+_netstat_mrt_free(struct mroute_type *mrtp)
+{
+	_netstat_rat_free(mrtp->mrt_origin);
+	_netstat_rat_free(mrtp->mrt_group);
+	free(mrtp);
+}
+
+struct mroute_type *
+_netstat_mrt_allocate(struct mroute_type_list *list)
+{
+	struct mroute_type *mrtp;
+
+	mrtp = malloc(sizeof(*mrtp));
+	if (mrtp == NULL)
+		return (NULL);
+
+	bzero(mrtp, sizeof(*mrtp));
+	TAILQ_INSERT_TAIL(&list->mrtl_list, mrtp, mrt_list);
+	list->mrtl_length += 1;
+	return (mrtp);
+}
+
+struct mroute_type_list *
+netstat_mrtl_alloc(void)
+{
+	struct mroute_type_list *mrtlp;
+
+	mrtlp = malloc(sizeof(*mrtlp));
+	if (mrtlp == NULL)
+		return (NULL);
+
+	TAILQ_INIT(&mrtlp->mrtl_list);
+	mrtlp->mrtl_error = NETSTAT_ERROR_UNDEFINED;
+	mrtlp->mrtl_length = 0;
+	return (mrtlp);
+}
+
+void
+netstat_mrtl_free(struct mroute_type_list *mrtlp)
+{
+	_netstat_mrtl_empty(mrtlp);
+	free(mrtlp);
+}
+
+int
+netstat_mrtl_geterror(const struct mroute_type_list *mrtlp)
+{
+	return (mrtlp->mrtl_error);
+}
+
+int
+netstat_mrtl_length(const struct mroute_type_list *mrtlp)
+{
+	return (mrtlp->mrtl_length);
+}
+
+int
+netstat_mrti_alloc(struct mroute_type_list *list,
+    struct mroute_type_iterator **iterator)
+{
+	struct mroute_type_iterator *mrtip;
+
+	mrtip = malloc(sizeof(*mrtip));
+	if (mrtip == NULL)
+		return (-1);
+
+	bzero(mrtip, sizeof(*mrtip));
+	mrtip->mrti_list = list;
+	mrtip->mrti_first = TAILQ_FIRST(&list->mrtl_list);
+	if (mrtip->mrti_first != NULL)
+		mrtip->mrti_next = TAILQ_NEXT(mrtip->mrti_first, mrt_list);
+	*iterator = mrtip;
+	return (0);
+}
+
+const struct mroute_type *
+netstat_mrti_first(struct mroute_type_iterator *mrtip)
+{
+	if (mrtip->mrti_first != NULL)
+		mrtip->mrti_next = TAILQ_NEXT(mrtip->mrti_first, mrt_list);
+	return (mrtip->mrti_first);
+}
+
+const struct mroute_type *
+netstat_mrti_next(struct mroute_type_iterator *mrtip)
+{
+	const struct mroute_type *mrtp;
+
+	mrtp = mrtip->mrti_next;
+	if (mrtip->mrti_next != NULL)
+		mrtip->mrti_next = TAILQ_NEXT(mrtip->mrti_next, mrt_list);
+
+	return (mrtp);
+}
+
+void
+netstat_mrti_free(struct mroute_type_iterator *mrtip)
+{
+	free(mrtip);
+}
+
+const struct routeaddr_type *
+netstat_mrt_get_origin(const struct mroute_type *mrtp)
+{
+	return (mrtp->mrt_origin);
+}
+
+const struct routeaddr_type *
+netstat_mrt_get_group(const struct mroute_type *mrtp)
+{
+	return (mrtp->mrt_group);
+}
+
+u_int64_t
+netstat_mrt_get_packets(const struct mroute_type *mrtp)
+{
+	return (mrtp->mrt_pkt_cnt);
+}
+
+u_int64_t
+netstat_mrt_get_bytes(const struct mroute_type *mrtp)
+{
+	return (mrtp->mrt_byte_cnt);
+}
+
+u_int64_t
+netstat_mrt_get_waitings(const struct mroute_type *mrtp)
+{
+	return (mrtp->mrt_nstall);
+}
+
+u_int32_t
+netstat_mrt_get_parent(const struct mroute_type *mrtp)
+{
+	return (mrtp->mrt_parent);
+}
+
+u_int8_t
+netstat_mrt_get_ttl(const struct mroute_type *mrtp, int i)
+{
+	if (0 <= i && i < MRTTYPE_MAXVIFS)
+		return (mrtp->mrt_ttls[i]);
+	return (0);
+}
+
+int
+netstat_mrt_get_is_mif_set(const struct mroute_type *mrtp, u_int32_t mifi)
+{
+	return (IF_ISSET(mifi, &mrtp->mrt_ifset));
+}
+
+
 static	const char *icmpnames[ICMP_MAXTYPE + 1] = {
 	"echo reply",			/* RFC 792 */
 	"#1",



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200908190311.n7J3BRLl066587>