SYSCTL_STRUCT(_net_stats, OID_AUTO, stats, CTLFLAG_RD | CTLFLAG_LOCKED,
&nstat_stats, nstat_stats, "");
-
enum
{
NSTAT_FLAG_CLEANUP = (1 << 0),
static bool nstat_control_reporting_allowed(nstat_control_state *state, nstat_src *src);
static boolean_t nstat_control_begin_query(nstat_control_state *state, const nstat_msg_hdr *hdrp);
static u_int16_t nstat_control_end_query(nstat_control_state *state, nstat_src *last_src, boolean_t partial);
+static void nstat_ifnet_report_ecn_stats(void);
static u_int32_t nstat_udp_watchers = 0;
static u_int32_t nstat_tcp_watchers = 0;
break;
case IFRTYPE_FUNCTIONAL_CELLULAR:
flags |= NSTAT_IFNET_IS_CELLULAR;
+ if (inp->inp_socket != NULL &&
+ (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK))
+ flags |= NSTAT_IFNET_VIA_CELLFALLBACK;
break;
}
lck_rw_done(&ifp->if_link_status_lock);
}
+static u_int64_t nstat_ifnet_last_report_time = 0;
+extern int tcp_report_stats_interval;
+
+static void
+nstat_ifnet_compute_percentages(struct if_tcp_ecn_perf_stat *ifst)
+{
+ /* Retransmit percentage */
+ if (ifst->total_rxmitpkts > 0 && ifst->total_txpkts > 0) {
+ /* shift by 10 for precision */
+ ifst->rxmit_percent =
+ ((ifst->total_rxmitpkts << 10) * 100) / ifst->total_txpkts;
+ } else {
+ ifst->rxmit_percent = 0;
+ }
+
+ /* Out-of-order percentage */
+ if (ifst->total_oopkts > 0 && ifst->total_rxpkts > 0) {
+ /* shift by 10 for precision */
+ ifst->oo_percent =
+ ((ifst->total_oopkts << 10) * 100) / ifst->total_rxpkts;
+ } else {
+ ifst->oo_percent = 0;
+ }
+
+ /* Reorder percentage */
+ if (ifst->total_reorderpkts > 0 &&
+ (ifst->total_txpkts + ifst->total_rxpkts) > 0) {
+ /* shift by 10 for precision */
+ ifst->reorder_percent =
+ ((ifst->total_reorderpkts << 10) * 100) /
+ (ifst->total_txpkts + ifst->total_rxpkts);
+ } else {
+ ifst->reorder_percent = 0;
+ }
+}
+
+static void
+nstat_ifnet_normalize_counter(struct if_tcp_ecn_stat *if_st)
+{
+ u_int64_t ecn_on_conn, ecn_off_conn;
+
+ if (if_st == NULL)
+ return;
+ ecn_on_conn = if_st->ecn_client_success +
+ if_st->ecn_server_success;
+ ecn_off_conn = if_st->ecn_off_conn +
+ (if_st->ecn_client_setup - if_st->ecn_client_success) +
+ (if_st->ecn_server_setup - if_st->ecn_server_success);
+
+ /*
+ * report sack episodes, rst_drop and rxmit_drop
+ * as a ratio per connection, shift by 10 for precision
+ */
+ if (ecn_on_conn > 0) {
+ if_st->ecn_on.sack_episodes =
+ (if_st->ecn_on.sack_episodes << 10) / ecn_on_conn;
+ if_st->ecn_on.rst_drop =
+ (if_st->ecn_on.rst_drop << 10) * 100 / ecn_on_conn;
+ if_st->ecn_on.rxmit_drop =
+ (if_st->ecn_on.rxmit_drop << 10) * 100 / ecn_on_conn;
+ } else {
+ /* set to zero, just in case */
+ if_st->ecn_on.sack_episodes = 0;
+ if_st->ecn_on.rst_drop = 0;
+ if_st->ecn_on.rxmit_drop = 0;
+ }
+
+ if (ecn_off_conn > 0) {
+ if_st->ecn_off.sack_episodes =
+ (if_st->ecn_off.sack_episodes << 10) / ecn_off_conn;
+ if_st->ecn_off.rst_drop =
+ (if_st->ecn_off.rst_drop << 10) * 100 / ecn_off_conn;
+ if_st->ecn_off.rxmit_drop =
+ (if_st->ecn_off.rxmit_drop << 10) * 100 / ecn_off_conn;
+ } else {
+ if_st->ecn_off.sack_episodes = 0;
+ if_st->ecn_off.rst_drop = 0;
+ if_st->ecn_off.rxmit_drop = 0;
+ }
+ if_st->ecn_total_conn = ecn_off_conn + ecn_on_conn;
+}
+
+void
+nstat_ifnet_report_ecn_stats(void)
+{
+ u_int64_t uptime, last_report_time;
+ struct nstat_sysinfo_data data;
+ struct nstat_sysinfo_ifnet_ecn_stats *st;
+ struct ifnet *ifp;
+
+ uptime = net_uptime();
+
+ if ((int)(uptime - nstat_ifnet_last_report_time) <
+ tcp_report_stats_interval)
+ return;
+
+ last_report_time = nstat_ifnet_last_report_time;
+ nstat_ifnet_last_report_time = uptime;
+ data.flags = NSTAT_SYSINFO_IFNET_ECN_STATS;
+ st = &data.u.ifnet_ecn_stats;
+
+ ifnet_head_lock_shared();
+ TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
+ if (ifp->if_ipv4_stat == NULL || ifp->if_ipv6_stat == NULL)
+ continue;
+
+ if ((ifp->if_refflags & (IFRF_ATTACHED | IFRF_DETACHING)) !=
+ IFRF_ATTACHED)
+ continue;
+
+ /* Limit reporting to Wifi, Ethernet and cellular. */
+ if (!(IFNET_IS_ETHERNET(ifp) || IFNET_IS_CELLULAR(ifp)))
+ continue;
+
+ bzero(st, sizeof(*st));
+ if (IFNET_IS_CELLULAR(ifp)) {
+ st->ifnet_type = NSTAT_IFNET_ECN_TYPE_CELLULAR;
+ } else if (IFNET_IS_WIFI(ifp)) {
+ st->ifnet_type = NSTAT_IFNET_ECN_TYPE_WIFI;
+ } else {
+ st->ifnet_type = NSTAT_IFNET_ECN_TYPE_ETHERNET;
+ }
+
+ /* skip if there was no update since last report */
+ if (ifp->if_ipv4_stat->timestamp <= 0 ||
+ ifp->if_ipv4_stat->timestamp < last_report_time)
+ goto v6;
+ st->ifnet_proto = NSTAT_IFNET_ECN_PROTO_IPV4;
+ /* compute percentages using packet counts */
+ nstat_ifnet_compute_percentages(&ifp->if_ipv4_stat->ecn_on);
+ nstat_ifnet_compute_percentages(&ifp->if_ipv4_stat->ecn_off);
+ nstat_ifnet_normalize_counter(ifp->if_ipv4_stat);
+
+ bcopy(ifp->if_ipv4_stat, &st->ecn_stat,
+ sizeof(st->ecn_stat));
+ nstat_sysinfo_send_data(&data);
+ bzero(ifp->if_ipv4_stat, sizeof(*ifp->if_ipv4_stat));
+
+v6:
+ /* skip if there was no update since last report */
+ if (ifp->if_ipv6_stat->timestamp <= 0 ||
+ ifp->if_ipv6_stat->timestamp < last_report_time)
+ continue;
+ st->ifnet_proto = NSTAT_IFNET_ECN_PROTO_IPV6;
+
+ /* compute percentages using packet counts */
+ nstat_ifnet_compute_percentages(&ifp->if_ipv6_stat->ecn_on);
+ nstat_ifnet_compute_percentages(&ifp->if_ipv6_stat->ecn_off);
+ nstat_ifnet_normalize_counter(ifp->if_ipv6_stat);
+
+ bcopy(ifp->if_ipv6_stat, &st->ecn_stat,
+ sizeof(st->ecn_stat));
+ nstat_sysinfo_send_data(&data);
+
+ /* Zero the stats in ifp */
+ bzero(ifp->if_ipv6_stat, sizeof(*ifp->if_ipv6_stat));
+ }
+ ifnet_head_done();
+
+}
+
static errno_t
nstat_ifnet_copy_descriptor(
nstat_provider_cookie_t cookie,
nstat_sysinfo_data *data)
{
nstat_msg_sysinfo_counts *syscnt = NULL;
- size_t allocsize = 0, countsize = 0, nkeyvals = 0;
+ size_t allocsize = 0, countsize = 0, nkeyvals = 0, finalsize = 0;
nstat_sysinfo_keyval *kv;
errno_t result = 0;
size_t i = 0;
allocsize = offsetof(nstat_msg_sysinfo_counts, counts);
countsize = offsetof(nstat_sysinfo_counts, nstat_sysinfo_keyvals);
+ finalsize = allocsize;
/* get number of key-vals for each kind of stat */
switch (data->flags)
nkeyvals = sizeof(struct nstat_sysinfo_tcp_stats) /
sizeof(u_int32_t);
break;
+ case NSTAT_SYSINFO_IFNET_ECN_STATS:
+ nkeyvals = (sizeof(struct if_tcp_ecn_stat) /
+ sizeof(u_int64_t));
+
+ /* Two more keys for ifnet type and proto */
+ nkeyvals += 2;
+ break;
default:
return;
}
if (syscnt == NULL)
return;
bzero(syscnt, allocsize);
-
- syscnt->hdr.type = NSTAT_MSG_TYPE_SYSINFO_COUNTS;
- syscnt->hdr.length = allocsize;
- syscnt->counts.nstat_sysinfo_len = countsize;
kv = (nstat_sysinfo_keyval *) &syscnt->counts.nstat_sysinfo_keyvals;
switch (data->flags)
nstat_set_keyval_scalar(&kv[i++],
NSTAT_SYSINFO_ECN_CONN_NOPL_CE,
data->u.tcp_stats.ecn_conn_nopl_ce);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_FALLBACK_SYNLOSS,
+ data->u.tcp_stats.ecn_fallback_synloss);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_FALLBACK_REORDER,
+ data->u.tcp_stats.ecn_fallback_reorder);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_FALLBACK_CE,
+ data->u.tcp_stats.ecn_fallback_ce);
nstat_set_keyval_scalar(&kv[i++],
NSTAT_SYSINFO_TFO_SYN_DATA_RCV,
data->u.tcp_stats.tfo_syn_data_rcv);
nstat_set_keyval_scalar(&kv[i++],
NSTAT_SYSINFO_TFO_BLACKHOLE,
data->u.tcp_stats.tfo_blackhole);
-
VERIFY(i == nkeyvals);
break;
}
+ case NSTAT_SYSINFO_IFNET_ECN_STATS:
+ {
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_TYPE,
+ data->u.ifnet_ecn_stats.ifnet_type);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_PROTO,
+ data->u.ifnet_ecn_stats.ifnet_proto);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_CLIENT_SETUP,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_client_setup);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_SERVER_SETUP,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_server_setup);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_CLIENT_SUCCESS,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_client_success);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_SERVER_SUCCESS,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_server_success);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_PEER_NOSUPPORT,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_peer_nosupport);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_SYN_LOST,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_syn_lost);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_SYNACK_LOST,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_synack_lost);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_RECV_CE,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_recv_ce);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_RECV_ECE,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_recv_ece);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_CONN_RECV_CE,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_conn_recv_ce);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_CONN_RECV_ECE,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_conn_recv_ece);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_CONN_PLNOCE,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_conn_plnoce);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_CONN_PLCE,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_conn_plce);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_CONN_NOPLCE,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_conn_noplce);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_FALLBACK_SYNLOSS,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_fallback_synloss);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_FALLBACK_REORDER,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_fallback_reorder);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_FALLBACK_CE,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_fallback_ce);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_ON_RTT_AVG,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_on.rtt_avg);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_ON_RTT_VAR,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_on.rtt_var);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_ON_OOPERCENT,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_on.oo_percent);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_ON_SACK_EPISODE,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_on.sack_episodes);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_ON_REORDER_PERCENT,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_on.reorder_percent);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_ON_RXMIT_PERCENT,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_on.rxmit_percent);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_ON_RXMIT_DROP,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_on.rxmit_drop);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_OFF_RTT_AVG,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_off.rtt_avg);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_OFF_RTT_VAR,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_off.rtt_var);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_OFF_OOPERCENT,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_off.oo_percent);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_OFF_SACK_EPISODE,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_off.sack_episodes);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_OFF_REORDER_PERCENT,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_off.reorder_percent);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_OFF_RXMIT_PERCENT,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_off.rxmit_percent);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_OFF_RXMIT_DROP,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_off.rxmit_drop);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_ON_TOTAL_TXPKTS,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_on.total_txpkts);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_ON_TOTAL_RXMTPKTS,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_on.total_rxmitpkts);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_ON_TOTAL_RXPKTS,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_on.total_rxpkts);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_ON_TOTAL_OOPKTS,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_on.total_oopkts);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_ON_DROP_RST,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_on.rst_drop);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_OFF_TOTAL_TXPKTS,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_off.total_txpkts);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_OFF_TOTAL_RXMTPKTS,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_off.total_rxmitpkts);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_OFF_TOTAL_RXPKTS,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_off.total_rxpkts);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_OFF_TOTAL_OOPKTS,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_off.total_oopkts);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_OFF_DROP_RST,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_off.rst_drop);
+ nstat_set_keyval_scalar(&kv[i++],
+ NSTAT_SYSINFO_ECN_IFNET_TOTAL_CONN,
+ data->u.ifnet_ecn_stats.ecn_stat.ecn_total_conn);
+ break;
+ }
}
-
if (syscnt != NULL)
{
+ VERIFY(i > 0 && i <= nkeyvals);
+ countsize = offsetof(nstat_sysinfo_counts,
+ nstat_sysinfo_keyvals) +
+ sizeof(nstat_sysinfo_keyval) * i;
+ finalsize += countsize;
+ syscnt->hdr.type = NSTAT_MSG_TYPE_SYSINFO_COUNTS;
+ syscnt->hdr.length = finalsize;
+ syscnt->counts.nstat_sysinfo_len = countsize;
+
result = ctl_enqueuedata(control->ncs_kctl,
- control->ncs_unit, syscnt, allocsize, CTL_DATA_EOR);
+ control->ncs_unit, syscnt, finalsize, CTL_DATA_EOR);
if (result != 0)
{
nstat_stats.nstat_sysinfofailures += 1;
{
mbuf_report_peak_usage();
tcp_report_stats();
+ nstat_ifnet_report_ecn_stats();
}
#pragma mark -- Kernel Control Socket --
nstat_control_state *state)
{
errno_t result = 0;
- if (state->ncs_accumulated && mbuf_len(state->ncs_accumulated))
+ if (state->ncs_accumulated != NULL && mbuf_len(state->ncs_accumulated) > 0)
{
mbuf_pkthdr_setlen(state->ncs_accumulated, mbuf_len(state->ncs_accumulated));
result = ctl_enqueuembuf(state->ncs_kctl, state->ncs_unit, state->ncs_accumulated, CTL_DATA_EOR);
- if (result != 0 && nstat_debug)
+ if (result != 0)
{
nstat_stats.nstat_flush_accumulated_msgs_failures++;
if (nstat_debug != 0)