aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/outqueue.c
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2016-07-09 07:47:45 -0400
committerDavid S. Miller <davem@davemloft.net>2016-07-11 16:25:39 -0400
commit8dbdf1f5b09cb22560e7c7173b52fe3c631046bd (patch)
treecb51b8283e24aa2ed014dbbc621a2dc86f9c91de /net/sctp/outqueue.c
parent01aadb3af6e1b10970c1f7e510b5097c8f725d64 (diff)
sctp: implement prsctp PRIO policy
prsctp PRIO policy is a policy to abandon lower priority chunks when asoc doesn't have enough snd buffer, so that the current chunk with higher priority can be queued successfully. Similar to TTL/RTX policy, we will set the priority of the chunk to prsctp_param with sinfo->sinfo_timetolive in sctp_set_prsctp_policy(). So if PRIO policy is enabled, msg->expire_at won't work. asoc->sent_cnt_removable will record how many chunks can be checked to remove. If priority policy is enabled, when the chunk is queued into the out_queue, we will increase sent_cnt_removable. When the chunk is moved to abandon_queue or dequeue and free, we will decrease sent_cnt_removable. In sctp_sendmsg, we will check if there is enough snd buffer for current msg and if sent_cnt_removable is not 0. Then try to abandon chunks in sctp_prune_prsctp when sendmsg from the retransmit/transmited queue, and free chunks from out_queue in right order until the abandon+free size > msg_len - sctp_wfree. For the abandon size, we have to wait until it sends FORWARD TSN, receives the sack and the chunks are really freed. Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/outqueue.c')
-rw-r--r--net/sctp/outqueue.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 084718f9b3da..72e54a416af6 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -326,6 +326,9 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk, gfp_t gfp)
326 326
327 sctp_chunk_hold(chunk); 327 sctp_chunk_hold(chunk);
328 sctp_outq_tail_data(q, chunk); 328 sctp_outq_tail_data(q, chunk);
329 if (chunk->asoc->prsctp_enable &&
330 SCTP_PR_PRIO_ENABLED(chunk->sinfo.sinfo_flags))
331 chunk->asoc->sent_cnt_removable++;
329 if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) 332 if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
330 SCTP_INC_STATS(net, SCTP_MIB_OUTUNORDERCHUNKS); 333 SCTP_INC_STATS(net, SCTP_MIB_OUTUNORDERCHUNKS);
331 else 334 else
@@ -372,6 +375,96 @@ static void sctp_insert_list(struct list_head *head, struct list_head *new)
372 list_add_tail(new, head); 375 list_add_tail(new, head);
373} 376}
374 377
378static int sctp_prsctp_prune_sent(struct sctp_association *asoc,
379 struct sctp_sndrcvinfo *sinfo,
380 struct list_head *queue, int msg_len)
381{
382 struct sctp_chunk *chk, *temp;
383
384 list_for_each_entry_safe(chk, temp, queue, transmitted_list) {
385 if (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) ||
386 chk->prsctp_param <= sinfo->sinfo_timetolive)
387 continue;
388
389 list_del_init(&chk->transmitted_list);
390 sctp_insert_list(&asoc->outqueue.abandoned,
391 &chk->transmitted_list);
392
393 asoc->sent_cnt_removable--;
394 asoc->abandoned_sent[SCTP_PR_INDEX(PRIO)]++;
395
396 if (!chk->tsn_gap_acked) {
397 if (chk->transport)
398 chk->transport->flight_size -=
399 sctp_data_size(chk);
400 asoc->outqueue.outstanding_bytes -= sctp_data_size(chk);
401 }
402
403 msg_len -= SCTP_DATA_SNDSIZE(chk) +
404 sizeof(struct sk_buff) +
405 sizeof(struct sctp_chunk);
406 if (msg_len <= 0)
407 break;
408 }
409
410 return msg_len;
411}
412
413static int sctp_prsctp_prune_unsent(struct sctp_association *asoc,
414 struct sctp_sndrcvinfo *sinfo,
415 struct list_head *queue, int msg_len)
416{
417 struct sctp_chunk *chk, *temp;
418
419 list_for_each_entry_safe(chk, temp, queue, list) {
420 if (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) ||
421 chk->prsctp_param <= sinfo->sinfo_timetolive)
422 continue;
423
424 list_del_init(&chk->list);
425 asoc->sent_cnt_removable--;
426 asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++;
427
428 msg_len -= SCTP_DATA_SNDSIZE(chk) +
429 sizeof(struct sk_buff) +
430 sizeof(struct sctp_chunk);
431 sctp_chunk_free(chk);
432 if (msg_len <= 0)
433 break;
434 }
435
436 return msg_len;
437}
438
439/* Abandon the chunks according their priorities */
440void sctp_prsctp_prune(struct sctp_association *asoc,
441 struct sctp_sndrcvinfo *sinfo, int msg_len)
442{
443 struct sctp_transport *transport;
444
445 if (!asoc->prsctp_enable || !asoc->sent_cnt_removable)
446 return;
447
448 msg_len = sctp_prsctp_prune_sent(asoc, sinfo,
449 &asoc->outqueue.retransmit,
450 msg_len);
451 if (msg_len <= 0)
452 return;
453
454 list_for_each_entry(transport, &asoc->peer.transport_addr_list,
455 transports) {
456 msg_len = sctp_prsctp_prune_sent(asoc, sinfo,
457 &transport->transmitted,
458 msg_len);
459 if (msg_len <= 0)
460 return;
461 }
462
463 sctp_prsctp_prune_unsent(asoc, sinfo,
464 &asoc->outqueue.out_chunk_list,
465 msg_len);
466}
467
375/* Mark all the eligible packets on a transport for retransmission. */ 468/* Mark all the eligible packets on a transport for retransmission. */
376void sctp_retransmit_mark(struct sctp_outq *q, 469void sctp_retransmit_mark(struct sctp_outq *q,
377 struct sctp_transport *transport, 470 struct sctp_transport *transport,
@@ -962,6 +1055,9 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
962 1055
963 /* Mark as failed send. */ 1056 /* Mark as failed send. */
964 sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); 1057 sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM);
1058 if (asoc->prsctp_enable &&
1059 SCTP_PR_PRIO_ENABLED(chunk->sinfo.sinfo_flags))
1060 asoc->sent_cnt_removable--;
965 sctp_chunk_free(chunk); 1061 sctp_chunk_free(chunk);
966 continue; 1062 continue;
967 } 1063 }
@@ -1251,6 +1347,9 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk)
1251 tsn = ntohl(tchunk->subh.data_hdr->tsn); 1347 tsn = ntohl(tchunk->subh.data_hdr->tsn);
1252 if (TSN_lte(tsn, ctsn)) { 1348 if (TSN_lte(tsn, ctsn)) {
1253 list_del_init(&tchunk->transmitted_list); 1349 list_del_init(&tchunk->transmitted_list);
1350 if (asoc->prsctp_enable &&
1351 SCTP_PR_PRIO_ENABLED(chunk->sinfo.sinfo_flags))
1352 asoc->sent_cnt_removable--;
1254 sctp_chunk_free(tchunk); 1353 sctp_chunk_free(tchunk);
1255 } 1354 }
1256 } 1355 }