Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 196d6759 authored by Michele Baldessari's avatar Michele Baldessari Committed by David S. Miller
Browse files

sctp: Add support to per-association statistics via a new SCTP_GET_ASSOC_STATS call



The current SCTP stack is lacking a mechanism to have per association
statistics. This is an implementation modeled after OpenSolaris'
SCTP_GET_ASSOC_STATS.

Userspace part will follow on lksctp if/when there is a general ACK on
this.
V4:
- Move ipackets++ before q->immediate.func() for consistency reasons
- Move sctp_max_rto() at the end of sctp_transport_update_rto() to avoid
  returning bogus RTO values
- return asoc->rto_min when max_obs_rto value has not changed

V3:
- Increase ictrlchunks in sctp_assoc_bh_rcv() as well
- Move ipackets++ to sctp_inq_push()
- return 0 when no rto updates took place since the last call

V2:
- Implement partial retrieval of stat struct to cope for future expansion
- Kill the rtxpackets counter as it cannot be precise anyway
- Rename outseqtsns to outofseqtsns to make it clearer that these are out
  of sequence unexpected TSNs
- Move asoc->ipackets++ under a lock to avoid potential miscounts
- Fold asoc->opackets++ into the already existing asoc check
- Kill unneeded (q->asoc) test when increasing rtxchunks
- Do not count octrlchunks if sending failed (SCTP_XMIT_OK != 0)
- Don't count SHUTDOWNs as SACKs
- Move SCTP_GET_ASSOC_STATS to the private space API
- Adjust the len check in sctp_getsockopt_assoc_stats() to allow for
  future struct growth
- Move association statistics in their own struct
- Update idupchunks when we send a SACK with dup TSNs
- return min_rto in max_rto when RTO has not changed. Also return the
  transport when max_rto last changed.

Signed-off: Michele Baldessari <michele@acksyn.org>
Acked-by: default avatarVlad Yasevich <vyasevich@gmail.com>

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 96070ae4
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -272,6 +272,18 @@ struct sctp_mib {
        unsigned long   mibs[SCTP_MIB_MAX];
};

/* helper function to track stats about max rto and related transport */
static inline void sctp_max_rto(struct sctp_association *asoc,
				struct sctp_transport *trans)
{
	if (asoc->stats.max_obs_rto < (__u64)trans->rto) {
		asoc->stats.max_obs_rto = trans->rto;
		memset(&asoc->stats.obs_rto_ipaddr, 0,
			sizeof(struct sockaddr_storage));
		memcpy(&asoc->stats.obs_rto_ipaddr, &trans->ipaddr,
			trans->af_specific->sockaddr_len);
	}
}

/* Print debugging messages.  */
#if SCTP_DEBUG
+36 −0
Original line number Diff line number Diff line
@@ -1312,6 +1312,40 @@ struct sctp_inithdr_host {
	__u32 initial_tsn;
};

/* SCTP_GET_ASSOC_STATS counters */
struct sctp_priv_assoc_stats {
	/* Maximum observed rto in the association during subsequent
	 * observations. Value is set to 0 if no RTO measurement took place
	 * The transport where the max_rto was observed is returned in
	 * obs_rto_ipaddr
	 */
	struct sockaddr_storage obs_rto_ipaddr;
	__u64 max_obs_rto;
	/* Total In and Out SACKs received and sent */
	__u64 isacks;
	__u64 osacks;
	/* Total In and Out packets received and sent */
	__u64 opackets;
	__u64 ipackets;
	/* Total retransmitted chunks */
	__u64 rtxchunks;
	/* TSN received > next expected */
	__u64 outofseqtsns;
	/* Duplicate Chunks received */
	__u64 idupchunks;
	/* Gap Ack Blocks received */
	__u64 gapcnt;
	/* Unordered data chunks sent and received */
	__u64 ouodchunks;
	__u64 iuodchunks;
	/* Ordered data chunks sent and received */
	__u64 oodchunks;
	__u64 iodchunks;
	/* Control chunks sent and received */
	__u64 octrlchunks;
	__u64 ictrlchunks;
};

/* RFC2960
 *
 * 12. Recommended Transmission Control Block (TCB) Parameters
@@ -1830,6 +1864,8 @@ struct sctp_association {

	__u8 need_ecne:1,	/* Need to send an ECNE Chunk? */
	     temp:1;		/* Is it a temporary association? */

	struct sctp_priv_assoc_stats stats;
};


+27 −0
Original line number Diff line number Diff line
@@ -107,6 +107,7 @@ typedef __s32 sctp_assoc_t;
#define SCTP_GET_LOCAL_ADDRS	109		/* Get all local address. */
#define SCTP_SOCKOPT_CONNECTX	110		/* CONNECTX requests. */
#define SCTP_SOCKOPT_CONNECTX3	111	/* CONNECTX requests (updated) */
#define SCTP_GET_ASSOC_STATS	112	/* Read only */

/*
 * 5.2.1 SCTP Initiation Structure (SCTP_INIT)
@@ -719,6 +720,32 @@ struct sctp_getaddrs {
	__u8			addrs[0]; /*output, variable size*/
};

/* A socket user request obtained via SCTP_GET_ASSOC_STATS that retrieves
 * association stats. All stats are counts except sas_maxrto and
 * sas_obs_rto_ipaddr. maxrto is the max observed rto + transport since
 * the last call. Will return 0 when RTO was not update since last call
 */
struct sctp_assoc_stats {
	sctp_assoc_t	sas_assoc_id;    /* Input */
					 /* Transport of observed max RTO */
	struct sockaddr_storage sas_obs_rto_ipaddr;
	__u64		sas_maxrto;      /* Maximum Observed RTO for period */
	__u64		sas_isacks;	 /* SACKs received */
	__u64		sas_osacks;	 /* SACKs sent */
	__u64		sas_opackets;	 /* Packets sent */
	__u64		sas_ipackets;	 /* Packets received */
	__u64		sas_rtxchunks;   /* Retransmitted Chunks */
	__u64		sas_outofseqtsns;/* TSN received > next expected */
	__u64		sas_idupchunks;  /* Dups received (ordered+unordered) */
	__u64		sas_gapcnt;      /* Gap Acknowledgements Received */
	__u64		sas_ouodchunks;  /* Unordered data chunks sent */
	__u64		sas_iuodchunks;  /* Unordered data chunks received */
	__u64		sas_oodchunks;	 /* Ordered data chunks sent */
	__u64		sas_iodchunks;	 /* Ordered data chunks received */
	__u64		sas_octrlchunks; /* Control chunks sent */
	__u64		sas_ictrlchunks; /* Control chunks received */
};

/* These are bit fields for msghdr->msg_flags.  See section 5.1.  */
/* On user space Linux, these live in <bits/socket.h> as an enum.  */
enum sctp_msg_flags {
+9 −1
Original line number Diff line number Diff line
@@ -321,6 +321,9 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
	asoc->default_timetolive = sp->default_timetolive;
	asoc->default_rcv_context = sp->default_rcv_context;

	/* SCTP_GET_ASSOC_STATS COUNTERS */
	memset(&asoc->stats, 0, sizeof(struct sctp_priv_assoc_stats));

	/* AUTH related initializations */
	INIT_LIST_HEAD(&asoc->endpoint_shared_keys);
	err = sctp_auth_asoc_copy_shkeys(ep, asoc, gfp);
@@ -760,6 +763,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,

	/* Set the transport's RTO.initial value */
	peer->rto = asoc->rto_initial;
	sctp_max_rto(asoc, peer);

	/* Set the peer's active state. */
	peer->state = peer_state;
@@ -1152,8 +1156,12 @@ static void sctp_assoc_bh_rcv(struct work_struct *work)
		 */
		if (sctp_chunk_is_data(chunk))
			asoc->peer.last_data_from = chunk->transport;
		else
		else {
			SCTP_INC_STATS(net, SCTP_MIB_INCTRLCHUNKS);
			asoc->stats.ictrlchunks++;
			if (chunk->chunk_hdr->type == SCTP_CID_SACK)
				asoc->stats.isacks++;
		}

		if (chunk->transport)
			chunk->transport->last_time_heard = jiffies;
+4 −1
Original line number Diff line number Diff line
@@ -480,8 +480,11 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work)
		 */
		if (asoc && sctp_chunk_is_data(chunk))
			asoc->peer.last_data_from = chunk->transport;
		else
		else {
			SCTP_INC_STATS(sock_net(ep->base.sk), SCTP_MIB_INCTRLCHUNKS);
			if (asoc)
				asoc->stats.ictrlchunks++;
		}

		if (chunk->transport)
			chunk->transport->last_time_heard = jiffies;
Loading