diff options
author | Michele Baldessari <michele@acksyn.org> | 2012-12-01 04:49:42 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-12-03 13:32:15 -0500 |
commit | 196d67593439b03088913227093e374235596e33 (patch) | |
tree | d8d1580673e3cf878d6db230bf86b71187bf3550 /net/sctp/socket.c | |
parent | 96070ae4d08eefe62ac534904ce21a01e1a5c9c4 (diff) | |
download | linux-3.10-196d67593439b03088913227093e374235596e33.tar.gz linux-3.10-196d67593439b03088913227093e374235596e33.tar.bz2 linux-3.10-196d67593439b03088913227093e374235596e33.zip |
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: Vlad Yasevich <vyasevich@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index bc1624913c4..9e65758cb03 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -611,6 +611,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk, 2*asoc->pathmtu, 4380)); trans->ssthresh = asoc->peer.i.a_rwnd; trans->rto = asoc->rto_initial; + sctp_max_rto(asoc, trans); trans->rtt = trans->srtt = trans->rttvar = 0; sctp_transport_route(trans, NULL, sctp_sk(asoc->base.sk)); @@ -5635,6 +5636,71 @@ static int sctp_getsockopt_paddr_thresholds(struct sock *sk, return 0; } +/* + * SCTP_GET_ASSOC_STATS + * + * This option retrieves local per endpoint statistics. It is modeled + * after OpenSolaris' implementation + */ +static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, + char __user *optval, + int __user *optlen) +{ + struct sctp_assoc_stats sas; + struct sctp_association *asoc = NULL; + + /* User must provide at least the assoc id */ + if (len < sizeof(sctp_assoc_t)) + return -EINVAL; + + if (copy_from_user(&sas, optval, len)) + return -EFAULT; + + asoc = sctp_id2assoc(sk, sas.sas_assoc_id); + if (!asoc) + return -EINVAL; + + sas.sas_rtxchunks = asoc->stats.rtxchunks; + sas.sas_gapcnt = asoc->stats.gapcnt; + sas.sas_outofseqtsns = asoc->stats.outofseqtsns; + sas.sas_osacks = asoc->stats.osacks; + sas.sas_isacks = asoc->stats.isacks; + sas.sas_octrlchunks = asoc->stats.octrlchunks; + sas.sas_ictrlchunks = asoc->stats.ictrlchunks; + sas.sas_oodchunks = asoc->stats.oodchunks; + sas.sas_iodchunks = asoc->stats.iodchunks; + sas.sas_ouodchunks = asoc->stats.ouodchunks; + sas.sas_iuodchunks = asoc->stats.iuodchunks; + sas.sas_idupchunks = asoc->stats.idupchunks; + sas.sas_opackets = asoc->stats.opackets; + sas.sas_ipackets = asoc->stats.ipackets; + + /* New high max rto observed, will return 0 if not a single + * RTO update took place. obs_rto_ipaddr will be bogus + * in such a case + */ + sas.sas_maxrto = asoc->stats.max_obs_rto; + memcpy(&sas.sas_obs_rto_ipaddr, &asoc->stats.obs_rto_ipaddr, + sizeof(struct sockaddr_storage)); + + /* Mark beginning of a new observation period */ + asoc->stats.max_obs_rto = asoc->rto_min; + + /* Allow the struct to grow and fill in as much as possible */ + len = min_t(size_t, len, sizeof(sas)); + + if (put_user(len, optlen)) + return -EFAULT; + + SCTP_DEBUG_PRINTK("sctp_getsockopt_assoc_stat(%d): %d\n", + len, sas.sas_assoc_id); + + if (copy_to_user(optval, &sas, len)) + return -EFAULT; + + return 0; +} + SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { @@ -5776,6 +5842,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, case SCTP_PEER_ADDR_THLDS: retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen); break; + case SCTP_GET_ASSOC_STATS: + retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; |