diff options
author | Michele Baldessari <michele@acksyn.org> | 2012-11-30 23:49:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-12-03 13:32:15 -0500 |
commit | 196d67593439b03088913227093e374235596e33 (patch) | |
tree | d8d1580673e3cf878d6db230bf86b71187bf3550 | |
parent | 96070ae4d08eefe62ac534904ce21a01e1a5c9c4 (diff) |
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>
-rw-r--r-- | include/net/sctp/sctp.h | 12 | ||||
-rw-r--r-- | include/net/sctp/structs.h | 36 | ||||
-rw-r--r-- | include/net/sctp/user.h | 27 | ||||
-rw-r--r-- | net/sctp/associola.c | 10 | ||||
-rw-r--r-- | net/sctp/endpointola.c | 5 | ||||
-rw-r--r-- | net/sctp/inqueue.c | 2 | ||||
-rw-r--r-- | net/sctp/output.c | 14 | ||||
-rw-r--r-- | net/sctp/outqueue.c | 12 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 5 | ||||
-rw-r--r-- | net/sctp/sm_sideeffect.c | 1 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 10 | ||||
-rw-r--r-- | net/sctp/socket.c | 69 | ||||
-rw-r--r-- | net/sctp/transport.c | 2 |
13 files changed, 192 insertions, 13 deletions
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 9c6414f553f9..7fdf298a47ef 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h | |||
@@ -272,6 +272,18 @@ struct sctp_mib { | |||
272 | unsigned long mibs[SCTP_MIB_MAX]; | 272 | unsigned long mibs[SCTP_MIB_MAX]; |
273 | }; | 273 | }; |
274 | 274 | ||
275 | /* helper function to track stats about max rto and related transport */ | ||
276 | static inline void sctp_max_rto(struct sctp_association *asoc, | ||
277 | struct sctp_transport *trans) | ||
278 | { | ||
279 | if (asoc->stats.max_obs_rto < (__u64)trans->rto) { | ||
280 | asoc->stats.max_obs_rto = trans->rto; | ||
281 | memset(&asoc->stats.obs_rto_ipaddr, 0, | ||
282 | sizeof(struct sockaddr_storage)); | ||
283 | memcpy(&asoc->stats.obs_rto_ipaddr, &trans->ipaddr, | ||
284 | trans->af_specific->sockaddr_len); | ||
285 | } | ||
286 | } | ||
275 | 287 | ||
276 | /* Print debugging messages. */ | 288 | /* Print debugging messages. */ |
277 | #if SCTP_DEBUG | 289 | #if SCTP_DEBUG |
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 2b2f61dd4036..c2521016d646 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h | |||
@@ -1312,6 +1312,40 @@ struct sctp_inithdr_host { | |||
1312 | __u32 initial_tsn; | 1312 | __u32 initial_tsn; |
1313 | }; | 1313 | }; |
1314 | 1314 | ||
1315 | /* SCTP_GET_ASSOC_STATS counters */ | ||
1316 | struct sctp_priv_assoc_stats { | ||
1317 | /* Maximum observed rto in the association during subsequent | ||
1318 | * observations. Value is set to 0 if no RTO measurement took place | ||
1319 | * The transport where the max_rto was observed is returned in | ||
1320 | * obs_rto_ipaddr | ||
1321 | */ | ||
1322 | struct sockaddr_storage obs_rto_ipaddr; | ||
1323 | __u64 max_obs_rto; | ||
1324 | /* Total In and Out SACKs received and sent */ | ||
1325 | __u64 isacks; | ||
1326 | __u64 osacks; | ||
1327 | /* Total In and Out packets received and sent */ | ||
1328 | __u64 opackets; | ||
1329 | __u64 ipackets; | ||
1330 | /* Total retransmitted chunks */ | ||
1331 | __u64 rtxchunks; | ||
1332 | /* TSN received > next expected */ | ||
1333 | __u64 outofseqtsns; | ||
1334 | /* Duplicate Chunks received */ | ||
1335 | __u64 idupchunks; | ||
1336 | /* Gap Ack Blocks received */ | ||
1337 | __u64 gapcnt; | ||
1338 | /* Unordered data chunks sent and received */ | ||
1339 | __u64 ouodchunks; | ||
1340 | __u64 iuodchunks; | ||
1341 | /* Ordered data chunks sent and received */ | ||
1342 | __u64 oodchunks; | ||
1343 | __u64 iodchunks; | ||
1344 | /* Control chunks sent and received */ | ||
1345 | __u64 octrlchunks; | ||
1346 | __u64 ictrlchunks; | ||
1347 | }; | ||
1348 | |||
1315 | /* RFC2960 | 1349 | /* RFC2960 |
1316 | * | 1350 | * |
1317 | * 12. Recommended Transmission Control Block (TCB) Parameters | 1351 | * 12. Recommended Transmission Control Block (TCB) Parameters |
@@ -1830,6 +1864,8 @@ struct sctp_association { | |||
1830 | 1864 | ||
1831 | __u8 need_ecne:1, /* Need to send an ECNE Chunk? */ | 1865 | __u8 need_ecne:1, /* Need to send an ECNE Chunk? */ |
1832 | temp:1; /* Is it a temporary association? */ | 1866 | temp:1; /* Is it a temporary association? */ |
1867 | |||
1868 | struct sctp_priv_assoc_stats stats; | ||
1833 | }; | 1869 | }; |
1834 | 1870 | ||
1835 | 1871 | ||
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 1b02d7ad453b..9a0ae091366d 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h | |||
@@ -107,6 +107,7 @@ typedef __s32 sctp_assoc_t; | |||
107 | #define SCTP_GET_LOCAL_ADDRS 109 /* Get all local address. */ | 107 | #define SCTP_GET_LOCAL_ADDRS 109 /* Get all local address. */ |
108 | #define SCTP_SOCKOPT_CONNECTX 110 /* CONNECTX requests. */ | 108 | #define SCTP_SOCKOPT_CONNECTX 110 /* CONNECTX requests. */ |
109 | #define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */ | 109 | #define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */ |
110 | #define SCTP_GET_ASSOC_STATS 112 /* Read only */ | ||
110 | 111 | ||
111 | /* | 112 | /* |
112 | * 5.2.1 SCTP Initiation Structure (SCTP_INIT) | 113 | * 5.2.1 SCTP Initiation Structure (SCTP_INIT) |
@@ -719,6 +720,32 @@ struct sctp_getaddrs { | |||
719 | __u8 addrs[0]; /*output, variable size*/ | 720 | __u8 addrs[0]; /*output, variable size*/ |
720 | }; | 721 | }; |
721 | 722 | ||
723 | /* A socket user request obtained via SCTP_GET_ASSOC_STATS that retrieves | ||
724 | * association stats. All stats are counts except sas_maxrto and | ||
725 | * sas_obs_rto_ipaddr. maxrto is the max observed rto + transport since | ||
726 | * the last call. Will return 0 when RTO was not update since last call | ||
727 | */ | ||
728 | struct sctp_assoc_stats { | ||
729 | sctp_assoc_t sas_assoc_id; /* Input */ | ||
730 | /* Transport of observed max RTO */ | ||
731 | struct sockaddr_storage sas_obs_rto_ipaddr; | ||
732 | __u64 sas_maxrto; /* Maximum Observed RTO for period */ | ||
733 | __u64 sas_isacks; /* SACKs received */ | ||
734 | __u64 sas_osacks; /* SACKs sent */ | ||
735 | __u64 sas_opackets; /* Packets sent */ | ||
736 | __u64 sas_ipackets; /* Packets received */ | ||
737 | __u64 sas_rtxchunks; /* Retransmitted Chunks */ | ||
738 | __u64 sas_outofseqtsns;/* TSN received > next expected */ | ||
739 | __u64 sas_idupchunks; /* Dups received (ordered+unordered) */ | ||
740 | __u64 sas_gapcnt; /* Gap Acknowledgements Received */ | ||
741 | __u64 sas_ouodchunks; /* Unordered data chunks sent */ | ||
742 | __u64 sas_iuodchunks; /* Unordered data chunks received */ | ||
743 | __u64 sas_oodchunks; /* Ordered data chunks sent */ | ||
744 | __u64 sas_iodchunks; /* Ordered data chunks received */ | ||
745 | __u64 sas_octrlchunks; /* Control chunks sent */ | ||
746 | __u64 sas_ictrlchunks; /* Control chunks received */ | ||
747 | }; | ||
748 | |||
722 | /* These are bit fields for msghdr->msg_flags. See section 5.1. */ | 749 | /* These are bit fields for msghdr->msg_flags. See section 5.1. */ |
723 | /* On user space Linux, these live in <bits/socket.h> as an enum. */ | 750 | /* On user space Linux, these live in <bits/socket.h> as an enum. */ |
724 | enum sctp_msg_flags { | 751 | enum sctp_msg_flags { |
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index b1ef3bc301a5..ba3f9cc4c047 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -321,6 +321,9 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
321 | asoc->default_timetolive = sp->default_timetolive; | 321 | asoc->default_timetolive = sp->default_timetolive; |
322 | asoc->default_rcv_context = sp->default_rcv_context; | 322 | asoc->default_rcv_context = sp->default_rcv_context; |
323 | 323 | ||
324 | /* SCTP_GET_ASSOC_STATS COUNTERS */ | ||
325 | memset(&asoc->stats, 0, sizeof(struct sctp_priv_assoc_stats)); | ||
326 | |||
324 | /* AUTH related initializations */ | 327 | /* AUTH related initializations */ |
325 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); | 328 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); |
326 | err = sctp_auth_asoc_copy_shkeys(ep, asoc, gfp); | 329 | err = sctp_auth_asoc_copy_shkeys(ep, asoc, gfp); |
@@ -760,6 +763,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, | |||
760 | 763 | ||
761 | /* Set the transport's RTO.initial value */ | 764 | /* Set the transport's RTO.initial value */ |
762 | peer->rto = asoc->rto_initial; | 765 | peer->rto = asoc->rto_initial; |
766 | sctp_max_rto(asoc, peer); | ||
763 | 767 | ||
764 | /* Set the peer's active state. */ | 768 | /* Set the peer's active state. */ |
765 | peer->state = peer_state; | 769 | peer->state = peer_state; |
@@ -1152,8 +1156,12 @@ static void sctp_assoc_bh_rcv(struct work_struct *work) | |||
1152 | */ | 1156 | */ |
1153 | if (sctp_chunk_is_data(chunk)) | 1157 | if (sctp_chunk_is_data(chunk)) |
1154 | asoc->peer.last_data_from = chunk->transport; | 1158 | asoc->peer.last_data_from = chunk->transport; |
1155 | else | 1159 | else { |
1156 | SCTP_INC_STATS(net, SCTP_MIB_INCTRLCHUNKS); | 1160 | SCTP_INC_STATS(net, SCTP_MIB_INCTRLCHUNKS); |
1161 | asoc->stats.ictrlchunks++; | ||
1162 | if (chunk->chunk_hdr->type == SCTP_CID_SACK) | ||
1163 | asoc->stats.isacks++; | ||
1164 | } | ||
1157 | 1165 | ||
1158 | if (chunk->transport) | 1166 | if (chunk->transport) |
1159 | chunk->transport->last_time_heard = jiffies; | 1167 | chunk->transport->last_time_heard = jiffies; |
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 1859e2bc83d1..32ab55b18281 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c | |||
@@ -480,8 +480,11 @@ normal: | |||
480 | */ | 480 | */ |
481 | if (asoc && sctp_chunk_is_data(chunk)) | 481 | if (asoc && sctp_chunk_is_data(chunk)) |
482 | asoc->peer.last_data_from = chunk->transport; | 482 | asoc->peer.last_data_from = chunk->transport; |
483 | else | 483 | else { |
484 | SCTP_INC_STATS(sock_net(ep->base.sk), SCTP_MIB_INCTRLCHUNKS); | 484 | SCTP_INC_STATS(sock_net(ep->base.sk), SCTP_MIB_INCTRLCHUNKS); |
485 | if (asoc) | ||
486 | asoc->stats.ictrlchunks++; | ||
487 | } | ||
485 | 488 | ||
486 | if (chunk->transport) | 489 | if (chunk->transport) |
487 | chunk->transport->last_time_heard = jiffies; | 490 | chunk->transport->last_time_heard = jiffies; |
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 397296fb156f..2d5ad280de38 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c | |||
@@ -104,6 +104,8 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk) | |||
104 | * on the BH related data structures. | 104 | * on the BH related data structures. |
105 | */ | 105 | */ |
106 | list_add_tail(&chunk->list, &q->in_chunk_list); | 106 | list_add_tail(&chunk->list, &q->in_chunk_list); |
107 | if (chunk->asoc) | ||
108 | chunk->asoc->stats.ipackets++; | ||
107 | q->immediate.func(&q->immediate); | 109 | q->immediate.func(&q->immediate); |
108 | } | 110 | } |
109 | 111 | ||
diff --git a/net/sctp/output.c b/net/sctp/output.c index 4e90188bf489..f5200a2ad852 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c | |||
@@ -311,6 +311,8 @@ static sctp_xmit_t __sctp_packet_append_chunk(struct sctp_packet *packet, | |||
311 | 311 | ||
312 | case SCTP_CID_SACK: | 312 | case SCTP_CID_SACK: |
313 | packet->has_sack = 1; | 313 | packet->has_sack = 1; |
314 | if (chunk->asoc) | ||
315 | chunk->asoc->stats.osacks++; | ||
314 | break; | 316 | break; |
315 | 317 | ||
316 | case SCTP_CID_AUTH: | 318 | case SCTP_CID_AUTH: |
@@ -584,11 +586,13 @@ int sctp_packet_transmit(struct sctp_packet *packet) | |||
584 | */ | 586 | */ |
585 | 587 | ||
586 | /* Dump that on IP! */ | 588 | /* Dump that on IP! */ |
587 | if (asoc && asoc->peer.last_sent_to != tp) { | 589 | if (asoc) { |
588 | /* Considering the multiple CPU scenario, this is a | 590 | asoc->stats.opackets++; |
589 | * "correcter" place for last_sent_to. --xguo | 591 | if (asoc->peer.last_sent_to != tp) |
590 | */ | 592 | /* Considering the multiple CPU scenario, this is a |
591 | asoc->peer.last_sent_to = tp; | 593 | * "correcter" place for last_sent_to. --xguo |
594 | */ | ||
595 | asoc->peer.last_sent_to = tp; | ||
592 | } | 596 | } |
593 | 597 | ||
594 | if (has_data) { | 598 | if (has_data) { |
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 1b4a7f8ec3fd..379c81dee9d1 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -667,6 +667,7 @@ redo: | |||
667 | chunk->fast_retransmit = SCTP_DONT_FRTX; | 667 | chunk->fast_retransmit = SCTP_DONT_FRTX; |
668 | 668 | ||
669 | q->empty = 0; | 669 | q->empty = 0; |
670 | q->asoc->stats.rtxchunks++; | ||
670 | break; | 671 | break; |
671 | } | 672 | } |
672 | 673 | ||
@@ -876,12 +877,14 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
876 | if (status != SCTP_XMIT_OK) { | 877 | if (status != SCTP_XMIT_OK) { |
877 | /* put the chunk back */ | 878 | /* put the chunk back */ |
878 | list_add(&chunk->list, &q->control_chunk_list); | 879 | list_add(&chunk->list, &q->control_chunk_list); |
879 | } else if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN) { | 880 | } else { |
881 | asoc->stats.octrlchunks++; | ||
880 | /* PR-SCTP C5) If a FORWARD TSN is sent, the | 882 | /* PR-SCTP C5) If a FORWARD TSN is sent, the |
881 | * sender MUST assure that at least one T3-rtx | 883 | * sender MUST assure that at least one T3-rtx |
882 | * timer is running. | 884 | * timer is running. |
883 | */ | 885 | */ |
884 | sctp_transport_reset_timers(transport); | 886 | if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN) |
887 | sctp_transport_reset_timers(transport); | ||
885 | } | 888 | } |
886 | break; | 889 | break; |
887 | 890 | ||
@@ -1055,6 +1058,10 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
1055 | */ | 1058 | */ |
1056 | if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING) | 1059 | if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING) |
1057 | chunk->chunk_hdr->flags |= SCTP_DATA_SACK_IMM; | 1060 | chunk->chunk_hdr->flags |= SCTP_DATA_SACK_IMM; |
1061 | if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) | ||
1062 | asoc->stats.ouodchunks++; | ||
1063 | else | ||
1064 | asoc->stats.oodchunks++; | ||
1058 | 1065 | ||
1059 | break; | 1066 | break; |
1060 | 1067 | ||
@@ -1162,6 +1169,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk) | |||
1162 | 1169 | ||
1163 | sack_ctsn = ntohl(sack->cum_tsn_ack); | 1170 | sack_ctsn = ntohl(sack->cum_tsn_ack); |
1164 | gap_ack_blocks = ntohs(sack->num_gap_ack_blocks); | 1171 | gap_ack_blocks = ntohs(sack->num_gap_ack_blocks); |
1172 | asoc->stats.gapcnt += gap_ack_blocks; | ||
1165 | /* | 1173 | /* |
1166 | * SFR-CACC algorithm: | 1174 | * SFR-CACC algorithm: |
1167 | * On receipt of a SACK the sender SHOULD execute the | 1175 | * On receipt of a SACK the sender SHOULD execute the |
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index e0f01a4e8cd6..e1c5fc2be6b8 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
@@ -804,10 +804,11 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc) | |||
804 | gabs); | 804 | gabs); |
805 | 805 | ||
806 | /* Add the duplicate TSN information. */ | 806 | /* Add the duplicate TSN information. */ |
807 | if (num_dup_tsns) | 807 | if (num_dup_tsns) { |
808 | aptr->stats.idupchunks += num_dup_tsns; | ||
808 | sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns, | 809 | sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns, |
809 | sctp_tsnmap_get_dups(map)); | 810 | sctp_tsnmap_get_dups(map)); |
810 | 811 | } | |
811 | /* Once we have a sack generated, check to see what our sack | 812 | /* Once we have a sack generated, check to see what our sack |
812 | * generation is, if its 0, reset the transports to 0, and reset | 813 | * generation is, if its 0, reset the transports to 0, and reset |
813 | * the association generation to 1 | 814 | * the association generation to 1 |
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index c0769569b05d..c9577754a708 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c | |||
@@ -542,6 +542,7 @@ static void sctp_do_8_2_transport_strike(sctp_cmd_seq_t *commands, | |||
542 | */ | 542 | */ |
543 | if (!is_hb || transport->hb_sent) { | 543 | if (!is_hb || transport->hb_sent) { |
544 | transport->rto = min((transport->rto * 2), transport->asoc->rto_max); | 544 | transport->rto = min((transport->rto * 2), transport->asoc->rto_max); |
545 | sctp_max_rto(asoc, transport); | ||
545 | } | 546 | } |
546 | } | 547 | } |
547 | 548 | ||
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index e92079d27eae..ebcd1eedb115 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -6133,6 +6133,8 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
6133 | /* The TSN is too high--silently discard the chunk and | 6133 | /* The TSN is too high--silently discard the chunk and |
6134 | * count on it getting retransmitted later. | 6134 | * count on it getting retransmitted later. |
6135 | */ | 6135 | */ |
6136 | if (chunk->asoc) | ||
6137 | chunk->asoc->stats.outofseqtsns++; | ||
6136 | return SCTP_IERROR_HIGH_TSN; | 6138 | return SCTP_IERROR_HIGH_TSN; |
6137 | } else if (tmp > 0) { | 6139 | } else if (tmp > 0) { |
6138 | /* This is a duplicate. Record it. */ | 6140 | /* This is a duplicate. Record it. */ |
@@ -6232,10 +6234,14 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
6232 | /* Note: Some chunks may get overcounted (if we drop) or overcounted | 6234 | /* Note: Some chunks may get overcounted (if we drop) or overcounted |
6233 | * if we renege and the chunk arrives again. | 6235 | * if we renege and the chunk arrives again. |
6234 | */ | 6236 | */ |
6235 | if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) | 6237 | if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { |
6236 | SCTP_INC_STATS(net, SCTP_MIB_INUNORDERCHUNKS); | 6238 | SCTP_INC_STATS(net, SCTP_MIB_INUNORDERCHUNKS); |
6237 | else { | 6239 | if (chunk->asoc) |
6240 | chunk->asoc->stats.iuodchunks++; | ||
6241 | } else { | ||
6238 | SCTP_INC_STATS(net, SCTP_MIB_INORDERCHUNKS); | 6242 | SCTP_INC_STATS(net, SCTP_MIB_INORDERCHUNKS); |
6243 | if (chunk->asoc) | ||
6244 | chunk->asoc->stats.iodchunks++; | ||
6239 | ordered = 1; | 6245 | ordered = 1; |
6240 | } | 6246 | } |
6241 | 6247 | ||
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index bc1624913c42..9e65758cb038 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, | |||
611 | 2*asoc->pathmtu, 4380)); | 611 | 2*asoc->pathmtu, 4380)); |
612 | trans->ssthresh = asoc->peer.i.a_rwnd; | 612 | trans->ssthresh = asoc->peer.i.a_rwnd; |
613 | trans->rto = asoc->rto_initial; | 613 | trans->rto = asoc->rto_initial; |
614 | sctp_max_rto(asoc, trans); | ||
614 | trans->rtt = trans->srtt = trans->rttvar = 0; | 615 | trans->rtt = trans->srtt = trans->rttvar = 0; |
615 | sctp_transport_route(trans, NULL, | 616 | sctp_transport_route(trans, NULL, |
616 | sctp_sk(asoc->base.sk)); | 617 | sctp_sk(asoc->base.sk)); |
@@ -5635,6 +5636,71 @@ static int sctp_getsockopt_paddr_thresholds(struct sock *sk, | |||
5635 | return 0; | 5636 | return 0; |
5636 | } | 5637 | } |
5637 | 5638 | ||
5639 | /* | ||
5640 | * SCTP_GET_ASSOC_STATS | ||
5641 | * | ||
5642 | * This option retrieves local per endpoint statistics. It is modeled | ||
5643 | * after OpenSolaris' implementation | ||
5644 | */ | ||
5645 | static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, | ||
5646 | char __user *optval, | ||
5647 | int __user *optlen) | ||
5648 | { | ||
5649 | struct sctp_assoc_stats sas; | ||
5650 | struct sctp_association *asoc = NULL; | ||
5651 | |||
5652 | /* User must provide at least the assoc id */ | ||
5653 | if (len < sizeof(sctp_assoc_t)) | ||
5654 | return -EINVAL; | ||
5655 | |||
5656 | if (copy_from_user(&sas, optval, len)) | ||
5657 | return -EFAULT; | ||
5658 | |||
5659 | asoc = sctp_id2assoc(sk, sas.sas_assoc_id); | ||
5660 | if (!asoc) | ||
5661 | return -EINVAL; | ||
5662 | |||
5663 | sas.sas_rtxchunks = asoc->stats.rtxchunks; | ||
5664 | sas.sas_gapcnt = asoc->stats.gapcnt; | ||
5665 | sas.sas_outofseqtsns = asoc->stats.outofseqtsns; | ||
5666 | sas.sas_osacks = asoc->stats.osacks; | ||
5667 | sas.sas_isacks = asoc->stats.isacks; | ||
5668 | sas.sas_octrlchunks = asoc->stats.octrlchunks; | ||
5669 | sas.sas_ictrlchunks = asoc->stats.ictrlchunks; | ||
5670 | sas.sas_oodchunks = asoc->stats.oodchunks; | ||
5671 | sas.sas_iodchunks = asoc->stats.iodchunks; | ||
5672 | sas.sas_ouodchunks = asoc->stats.ouodchunks; | ||
5673 | sas.sas_iuodchunks = asoc->stats.iuodchunks; | ||
5674 | sas.sas_idupchunks = asoc->stats.idupchunks; | ||
5675 | sas.sas_opackets = asoc->stats.opackets; | ||
5676 | sas.sas_ipackets = asoc->stats.ipackets; | ||
5677 | |||
5678 | /* New high max rto observed, will return 0 if not a single | ||
5679 | * RTO update took place. obs_rto_ipaddr will be bogus | ||
5680 | * in such a case | ||
5681 | */ | ||
5682 | sas.sas_maxrto = asoc->stats.max_obs_rto; | ||
5683 | memcpy(&sas.sas_obs_rto_ipaddr, &asoc->stats.obs_rto_ipaddr, | ||
5684 | sizeof(struct sockaddr_storage)); | ||
5685 | |||
5686 | /* Mark beginning of a new observation period */ | ||
5687 | asoc->stats.max_obs_rto = asoc->rto_min; | ||
5688 | |||
5689 | /* Allow the struct to grow and fill in as much as possible */ | ||
5690 | len = min_t(size_t, len, sizeof(sas)); | ||
5691 | |||
5692 | if (put_user(len, optlen)) | ||
5693 | return -EFAULT; | ||
5694 | |||
5695 | SCTP_DEBUG_PRINTK("sctp_getsockopt_assoc_stat(%d): %d\n", | ||
5696 | len, sas.sas_assoc_id); | ||
5697 | |||
5698 | if (copy_to_user(optval, &sas, len)) | ||
5699 | return -EFAULT; | ||
5700 | |||
5701 | return 0; | ||
5702 | } | ||
5703 | |||
5638 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | 5704 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, |
5639 | char __user *optval, int __user *optlen) | 5705 | char __user *optval, int __user *optlen) |
5640 | { | 5706 | { |
@@ -5776,6 +5842,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
5776 | case SCTP_PEER_ADDR_THLDS: | 5842 | case SCTP_PEER_ADDR_THLDS: |
5777 | retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen); | 5843 | retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen); |
5778 | break; | 5844 | break; |
5845 | case SCTP_GET_ASSOC_STATS: | ||
5846 | retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); | ||
5847 | break; | ||
5779 | default: | 5848 | default: |
5780 | retval = -ENOPROTOOPT; | 5849 | retval = -ENOPROTOOPT; |
5781 | break; | 5850 | break; |
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 206cf5238fd3..310f11eb2206 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
@@ -363,6 +363,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) | |||
363 | if (tp->rto > tp->asoc->rto_max) | 363 | if (tp->rto > tp->asoc->rto_max) |
364 | tp->rto = tp->asoc->rto_max; | 364 | tp->rto = tp->asoc->rto_max; |
365 | 365 | ||
366 | sctp_max_rto(tp->asoc, tp); | ||
366 | tp->rtt = rtt; | 367 | tp->rtt = rtt; |
367 | 368 | ||
368 | /* Reset rto_pending so that a new RTT measurement is started when a | 369 | /* Reset rto_pending so that a new RTT measurement is started when a |
@@ -620,6 +621,7 @@ void sctp_transport_reset(struct sctp_transport *t) | |||
620 | t->burst_limited = 0; | 621 | t->burst_limited = 0; |
621 | t->ssthresh = asoc->peer.i.a_rwnd; | 622 | t->ssthresh = asoc->peer.i.a_rwnd; |
622 | t->rto = asoc->rto_initial; | 623 | t->rto = asoc->rto_initial; |
624 | sctp_max_rto(asoc, t); | ||
623 | t->rtt = 0; | 625 | t->rtt = 0; |
624 | t->srtt = 0; | 626 | t->srtt = 0; |
625 | t->rttvar = 0; | 627 | t->rttvar = 0; |