Before when implementing sctp prsctp, SCTP_PR_STREAM_STATUS wasn't added, as it needs to save abandoned_(un)sent for every stream. After sctp stream reconf is added in sctp, assoc has structure sctp_stream_out to save per stream info. This patch is to add SCTP_PR_STREAM_STATUS by putting the prsctp per stream statistics into sctp_stream_out. v1->v2: fix an indent issue.
Unified · Split
| @@ -1315,6 +1315,8 @@ struct sctp_inithdr_host { · 1314 unmodified lines | ||
| 1315 | 1315 | struct sctp_stream_out { |
| 1316 | 1316 | __u16 ssn; |
| 1317 | 1317 | __u8 state; |
| 1318 | + __u64 abandoned_unsent[SCTP_PR_INDEX(MAX) + 1]; | |
| 1319 | + __u64 abandoned_sent[SCTP_PR_INDEX(MAX) + 1]; | |
| 1318 | 1320 | }; |
| 1319 | 1321 | |
| 1320 | 1322 | struct sctp_stream_in { |
| @@ -115,6 +115,7 @@ typedef __s32 sctp_assoc_t; · 114 unmodified lines | ||
| 115 | 115 | #define SCTP_PR_SUPPORTED 113 |
| 116 | 116 | #define SCTP_DEFAULT_PRINFO 114 |
| 117 | 117 | #define SCTP_PR_ASSOC_STATUS 115 |
| 118 | +#define SCTP_PR_STREAM_STATUS 116 | |
| 118 | 119 | #define SCTP_RECONFIG_SUPPORTED 117 |
| 119 | 120 | #define SCTP_ENABLE_STREAM_RESET 118 |
| 120 | 121 | #define SCTP_RESET_STREAMS 119 |
| @@ -306,14 +306,24 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk) · 305 unmodified lines | ||
| 306 | 306 | |
| 307 | 307 | if (SCTP_PR_TTL_ENABLED(chunk->sinfo.sinfo_flags) && |
| 308 | 308 | time_after(jiffies, chunk->msg->expires_at)) { |
| 309 | − if (chunk->sent_count) | |
| 309 | + struct sctp_stream_out *streamout = | |
| 310 | + &chunk->asoc->stream->out[chunk->sinfo.sinfo_stream]; | |
| 311 | + | |
| 312 | + if (chunk->sent_count) { | |
| 310 | 313 | chunk->asoc->abandoned_sent[SCTP_PR_INDEX(TTL)]++; |
| 311 | − else | |
| 314 | + streamout->abandoned_sent[SCTP_PR_INDEX(TTL)]++; | |
| 315 | + } else { | |
| 312 | 316 | chunk->asoc->abandoned_unsent[SCTP_PR_INDEX(TTL)]++; |
| 317 | + streamout->abandoned_unsent[SCTP_PR_INDEX(TTL)]++; | |
| 318 | + } | |
| 313 | 319 | return 1; |
| 314 | 320 | } else if (SCTP_PR_RTX_ENABLED(chunk->sinfo.sinfo_flags) && |
| 315 | 321 | chunk->sent_count > chunk->sinfo.sinfo_timetolive) { |
| 322 | + struct sctp_stream_out *streamout = | |
| 323 | + &chunk->asoc->stream->out[chunk->sinfo.sinfo_stream]; | |
| 324 | + | |
| 316 | 325 | chunk->asoc->abandoned_sent[SCTP_PR_INDEX(RTX)]++; |
| 326 | + streamout->abandoned_sent[SCTP_PR_INDEX(RTX)]++; | |
| 317 | 327 | return 1; |
| 318 | 328 | } else if (!SCTP_PR_POLICY(chunk->sinfo.sinfo_flags) && |
| 319 | 329 | chunk->msg->expires_at && |
| @@ -353,6 +353,8 @@ static int sctp_prsctp_prune_sent(struct sctp_association *asoc, · 352 unmodified lines | ||
| 353 | 353 | struct sctp_chunk *chk, *temp; |
| 354 | 354 | |
| 355 | 355 | list_for_each_entry_safe(chk, temp, queue, transmitted_list) { |
| 356 | + struct sctp_stream_out *streamout; | |
| 357 | + | |
| 356 | 358 | if (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) || |
| 357 | 359 | chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive) |
| 358 | 360 | continue; |
| @@ -361,8 +363,10 @@ static int sctp_prsctp_prune_sent(struct sctp_association *asoc, · 2 unmodified lines | ||
| 361 | 363 | sctp_insert_list(&asoc->outqueue.abandoned, |
| 362 | 364 | &chk->transmitted_list); |
| 363 | 365 | |
| 366 | + streamout = &asoc->stream->out[chk->sinfo.sinfo_stream]; | |
| 364 | 367 | asoc->sent_cnt_removable--; |
| 365 | 368 | asoc->abandoned_sent[SCTP_PR_INDEX(PRIO)]++; |
| 369 | + streamout->abandoned_sent[SCTP_PR_INDEX(PRIO)]++; | |
| 366 | 370 | |
| 367 | 371 | if (!chk->tsn_gap_acked) { |
| 368 | 372 | if (chk->transport) |
| @@ -396,6 +400,12 @@ static int sctp_prsctp_prune_unsent(struct sctp_association *asoc, · 27 unmodified lines | ||
| 396 | 400 | q->out_qlen -= chk->skb->len; |
| 397 | 401 | asoc->sent_cnt_removable--; |
| 398 | 402 | asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; |
| 403 | + if (chk->sinfo.sinfo_stream < asoc->stream->outcnt) { | |
| 404 | + struct sctp_stream_out *streamout = | |
| 405 | + &asoc->stream->out[chk->sinfo.sinfo_stream]; | |
| 406 | + | |
| 407 | + streamout->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; | |
| 408 | + } | |
| 399 | 409 | |
| 400 | 410 | msg_len -= SCTP_DATA_SNDSIZE(chk) + |
| 401 | 411 | sizeof(struct sk_buff) + |
| @@ -6576,6 +6576,61 @@ out: · 6575 unmodified lines | ||
| 6576 | 6576 | return retval; |
| 6577 | 6577 | } |
| 6578 | 6578 | |
| 6579 | +static int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len, | |
| 6580 | + char __user *optval, | |
| 6581 | + int __user *optlen) | |
| 6582 | +{ | |
| 6583 | + struct sctp_stream_out *streamout; | |
| 6584 | + struct sctp_association *asoc; | |
| 6585 | + struct sctp_prstatus params; | |
| 6586 | + int retval = -EINVAL; | |
| 6587 | + int policy; | |
| 6588 | + | |
| 6589 | + if (len < sizeof(params)) | |
| 6590 | + goto out; | |
| 6591 | + | |
| 6592 | + len = sizeof(params); | |
| 6593 | + if (copy_from_user(¶ms, optval, len)) { | |
| 6594 | + retval = -EFAULT; | |
| 6595 | + goto out; | |
| 6596 | + } | |
| 6597 | + | |
| 6598 | + policy = params.sprstat_policy; | |
| 6599 | + if (policy & ~SCTP_PR_SCTP_MASK) | |
| 6600 | + goto out; | |
| 6601 | + | |
| 6602 | + asoc = sctp_id2assoc(sk, params.sprstat_assoc_id); | |
| 6603 | + if (!asoc || params.sprstat_sid >= asoc->stream->outcnt) | |
| 6604 | + goto out; | |
| 6605 | + | |
| 6606 | + streamout = &asoc->stream->out[params.sprstat_sid]; | |
| 6607 | + if (policy == SCTP_PR_SCTP_NONE) { | |
| 6608 | + params.sprstat_abandoned_unsent = 0; | |
| 6609 | + params.sprstat_abandoned_sent = 0; | |
| 6610 | + for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) { | |
| 6611 | + params.sprstat_abandoned_unsent += | |
| 6612 | + streamout->abandoned_unsent[policy]; | |
| 6613 | + params.sprstat_abandoned_sent += | |
| 6614 | + streamout->abandoned_sent[policy]; | |
| 6615 | + } | |
| 6616 | + } else { | |
| 6617 | + params.sprstat_abandoned_unsent = | |
| 6618 | + streamout->abandoned_unsent[__SCTP_PR_INDEX(policy)]; | |
| 6619 | + params.sprstat_abandoned_sent = | |
| 6620 | + streamout->abandoned_sent[__SCTP_PR_INDEX(policy)]; | |
| 6621 | + } | |
| 6622 | + | |
| 6623 | + if (put_user(len, optlen) || copy_to_user(optval, ¶ms, len)) { | |
| 6624 | + retval = -EFAULT; | |
| 6625 | + goto out; | |
| 6626 | + } | |
| 6627 | + | |
| 6628 | + retval = 0; | |
| 6629 | + | |
| 6630 | +out: | |
| 6631 | + return retval; | |
| 6632 | +} | |
| 6633 | + | |
| 6579 | 6634 | static int sctp_getsockopt_reconfig_supported(struct sock *sk, int len, |
| 6580 | 6635 | char __user *optval, |
| 6581 | 6636 | int __user *optlen) |
| @@ -6825,6 +6880,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, · 243 unmodified lines | ||
| 6825 | 6880 | retval = sctp_getsockopt_pr_assocstatus(sk, len, optval, |
| 6826 | 6881 | optlen); |
| 6827 | 6882 | break; |
| 6883 | + case SCTP_PR_STREAM_STATUS: | |
| 6884 | + retval = sctp_getsockopt_pr_streamstatus(sk, len, optval, | |
| 6885 | + optlen); | |
| 6886 | + break; | |
| 6828 | 6887 | case SCTP_RECONFIG_SUPPORTED: |
| 6829 | 6888 | retval = sctp_getsockopt_reconfig_supported(sk, len, optval, |
| 6830 | 6889 | optlen); |