Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sctp: add SCTP_PR_STREAM_STATUS sockopt for prsctp

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.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Xin Long and committed by
David S. Miller
d229d48d cdccf74b

+84 -2
+2
include/net/sctp/structs.h
··· 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 {
+1
include/uapi/linux/sctp.h
··· 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
+12 -2
net/sctp/chunk.c
··· 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 &&
+10
net/sctp/outqueue.c
··· 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; ··· 363 361 sctp_insert_list(&asoc->outqueue.abandoned, 364 362 &chk->transmitted_list); 365 363 364 + streamout = &asoc->stream->out[chk->sinfo.sinfo_stream]; 366 365 asoc->sent_cnt_removable--; 367 366 asoc->abandoned_sent[SCTP_PR_INDEX(PRIO)]++; 367 + streamout->abandoned_sent[SCTP_PR_INDEX(PRIO)]++; 368 368 369 369 if (!chk->tsn_gap_acked) { 370 370 if (chk->transport) ··· 400 396 q->out_qlen -= chk->skb->len; 401 397 asoc->sent_cnt_removable--; 402 398 asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; 399 + if (chk->sinfo.sinfo_stream < asoc->stream->outcnt) { 400 + struct sctp_stream_out *streamout = 401 + &asoc->stream->out[chk->sinfo.sinfo_stream]; 402 + 403 + streamout->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; 404 + } 403 405 404 406 msg_len -= SCTP_DATA_SNDSIZE(chk) + 405 407 sizeof(struct sk_buff) +
+59
net/sctp/socket.c
··· 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(&params, 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, &params, 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) ··· 6879 6824 case SCTP_PR_ASSOC_STATUS: 6880 6825 retval = sctp_getsockopt_pr_assocstatus(sk, len, optval, 6881 6826 optlen); 6827 + break; 6828 + case SCTP_PR_STREAM_STATUS: 6829 + retval = sctp_getsockopt_pr_streamstatus(sk, len, optval, 6830 + optlen); 6882 6831 break; 6883 6832 case SCTP_RECONFIG_SUPPORTED: 6884 6833 retval = sctp_getsockopt_reconfig_supported(sk, len, optval,