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

tipc: introduce variable window congestion control

We introduce a simple variable window congestion control for links.
The algorithm is inspired by the Reno algorithm, covering both 'slow
start', 'congestion avoidance', and 'fast recovery' modes.

- We introduce hard lower and upper window limits per link, still
different and configurable per bearer type.

- We introduce a 'slow start theshold' variable, initially set to
the maximum window size.

- We let a link start at the minimum congestion window, i.e. in slow
start mode, and then let is grow rapidly (+1 per rceived ACK) until
it reaches the slow start threshold and enters congestion avoidance
mode.

- In congestion avoidance mode we increment the congestion window for
each window-size number of acked packets, up to a possible maximum
equal to the configured maximum window.

- For each non-duplicate NACK received, we drop back to fast recovery
mode, by setting the both the slow start threshold to and the
congestion window to (current_congestion_window / 2).

- If the timeout handler finds that the transmit queue has not moved
since the previous timeout, it drops the link back to slow start
and forces a probe containing the last sent sequence number to the
sent to the peer, so that this can discover the stale situation.

This change does in reality have effect only on unicast ethernet
transport, as we have seen that there is no room whatsoever for
increasing the window max size for the UDP bearer.
For now, we also choose to keep the limits for the broadcast link
unchanged and equal.

This algorithm seems to give a 50-100% throughput improvement for
messages larger than MTU.

Suggested-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jon Maloy and committed by
David S. Miller
16ad3f40 d3b09995

+161 -80
+6 -5
net/tipc/bcast.c
··· 562 562 return 0; 563 563 } 564 564 565 - static int tipc_bc_link_set_queue_limits(struct net *net, u32 limit) 565 + static int tipc_bc_link_set_queue_limits(struct net *net, u32 max_win) 566 566 { 567 567 struct tipc_link *l = tipc_bc_sndlink(net); 568 568 569 569 if (!l) 570 570 return -ENOPROTOOPT; 571 - if (limit < BCLINK_WIN_MIN) 572 - limit = BCLINK_WIN_MIN; 573 - if (limit > TIPC_MAX_LINK_WIN) 571 + if (max_win < BCLINK_WIN_MIN) 572 + max_win = BCLINK_WIN_MIN; 573 + if (max_win > TIPC_MAX_LINK_WIN) 574 574 return -EINVAL; 575 575 tipc_bcast_lock(net); 576 - tipc_link_set_queue_limits(l, limit); 576 + tipc_link_set_queue_limits(l, BCLINK_WIN_MIN, max_win); 577 577 tipc_bcast_unlock(net); 578 578 return 0; 579 579 } ··· 682 682 683 683 if (!tipc_link_bc_create(net, 0, 0, 684 684 FB_MTU, 685 + BCLINK_WIN_DEFAULT, 685 686 BCLINK_WIN_DEFAULT, 686 687 0, 687 688 &bb->inputq,
+6 -5
net/tipc/bearer.c
··· 311 311 312 312 b->identity = bearer_id; 313 313 b->tolerance = m->tolerance; 314 - b->window = m->window; 314 + b->min_win = m->min_win; 315 + b->max_win = m->max_win; 315 316 b->domain = disc_domain; 316 317 b->net_plane = bearer_id + 'A'; 317 318 b->priority = prio; ··· 797 796 goto prop_msg_full; 798 797 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_TOL, bearer->tolerance)) 799 798 goto prop_msg_full; 800 - if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, bearer->window)) 799 + if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, bearer->max_win)) 801 800 goto prop_msg_full; 802 801 if (bearer->media->type_id == TIPC_MEDIA_TYPE_UDP) 803 802 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_MTU, bearer->mtu)) ··· 1089 1088 if (props[TIPC_NLA_PROP_PRIO]) 1090 1089 b->priority = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); 1091 1090 if (props[TIPC_NLA_PROP_WIN]) 1092 - b->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 1091 + b->max_win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 1093 1092 if (props[TIPC_NLA_PROP_MTU]) { 1094 1093 if (b->media->type_id != TIPC_MEDIA_TYPE_UDP) 1095 1094 return -EINVAL; ··· 1143 1142 goto prop_msg_full; 1144 1143 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_TOL, media->tolerance)) 1145 1144 goto prop_msg_full; 1146 - if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, media->window)) 1145 + if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, media->max_win)) 1147 1146 goto prop_msg_full; 1148 1147 if (media->type_id == TIPC_MEDIA_TYPE_UDP) 1149 1148 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_MTU, media->mtu)) ··· 1276 1275 if (props[TIPC_NLA_PROP_PRIO]) 1277 1276 m->priority = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); 1278 1277 if (props[TIPC_NLA_PROP_WIN]) 1279 - m->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 1278 + m->max_win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 1280 1279 if (props[TIPC_NLA_PROP_MTU]) { 1281 1280 if (m->type_id != TIPC_MEDIA_TYPE_UDP) 1282 1281 return -EINVAL;
+4 -2
net/tipc/bearer.h
··· 119 119 char *raw); 120 120 u32 priority; 121 121 u32 tolerance; 122 - u32 window; 122 + u32 min_win; 123 + u32 max_win; 123 124 u32 mtu; 124 125 u32 type_id; 125 126 u32 hwaddr_len; ··· 159 158 struct packet_type pt; 160 159 struct rcu_head rcu; 161 160 u32 priority; 162 - u32 window; 161 + u32 min_win; 162 + u32 max_win; 163 163 u32 tolerance; 164 164 u32 domain; 165 165 u32 identity;
+2 -1
net/tipc/eth_media.c
··· 92 92 .raw2addr = tipc_eth_raw2addr, 93 93 .priority = TIPC_DEF_LINK_PRI, 94 94 .tolerance = TIPC_DEF_LINK_TOL, 95 - .window = TIPC_DEF_LINK_WIN, 95 + .min_win = TIPC_DEF_LINK_WIN, 96 + .max_win = TIPC_MAX_LINK_WIN, 96 97 .type_id = TIPC_MEDIA_TYPE_ETH, 97 98 .hwaddr_len = ETH_ALEN, 98 99 .name = "eth"
+4 -1
net/tipc/ib_media.c
··· 42 42 #include "core.h" 43 43 #include "bearer.h" 44 44 45 + #define TIPC_MAX_IB_LINK_WIN 500 46 + 45 47 /* convert InfiniBand address (media address format) media address to string */ 46 48 static int tipc_ib_addr2str(struct tipc_media_addr *a, char *str_buf, 47 49 int str_size) ··· 96 94 .raw2addr = tipc_ib_raw2addr, 97 95 .priority = TIPC_DEF_LINK_PRI, 98 96 .tolerance = TIPC_DEF_LINK_TOL, 99 - .window = TIPC_DEF_LINK_WIN, 97 + .min_win = TIPC_DEF_LINK_WIN, 98 + .max_win = TIPC_MAX_IB_LINK_WIN, 100 99 .type_id = TIPC_MEDIA_TYPE_IB, 101 100 .hwaddr_len = INFINIBAND_ALEN, 102 101 .name = "ib"
+123 -54
net/tipc/link.c
··· 164 164 struct sk_buff *target_bskb; 165 165 } backlog[5]; 166 166 u16 snd_nxt; 167 - u16 window; 168 167 169 168 /* Reception */ 170 169 u16 rcv_nxt; ··· 174 175 175 176 /* Congestion handling */ 176 177 struct sk_buff_head wakeupq; 178 + u16 window; 179 + u16 min_win; 180 + u16 ssthresh; 181 + u16 max_win; 182 + u16 cong_acks; 183 + u16 checkpoint; 177 184 178 185 /* Fragmentation/reassembly */ 179 186 struct sk_buff *reasm_buf; ··· 249 244 struct sk_buff_head *xmitq); 250 245 static void tipc_link_build_bc_init_msg(struct tipc_link *l, 251 246 struct sk_buff_head *xmitq); 252 - static bool tipc_link_release_pkts(struct tipc_link *l, u16 to); 247 + static int tipc_link_release_pkts(struct tipc_link *l, u16 to); 253 248 static u16 tipc_build_gap_ack_blks(struct tipc_link *l, void *data); 254 249 static int tipc_link_advance_transmq(struct tipc_link *l, u16 acked, u16 gap, 255 250 struct tipc_gap_ack_blks *ga, 256 251 struct sk_buff_head *xmitq); 257 - 252 + static void tipc_link_update_cwin(struct tipc_link *l, int released, 253 + bool retransmitted); 258 254 /* 259 255 * Simple non-static link routines (i.e. referenced outside this file) 260 256 */ ··· 314 308 return l->peer_bearer_id << 16 | l->bearer_id; 315 309 } 316 310 317 - int tipc_link_window(struct tipc_link *l) 311 + int tipc_link_min_win(struct tipc_link *l) 318 312 { 319 - return l->window; 313 + return l->min_win; 314 + } 315 + 316 + int tipc_link_max_win(struct tipc_link *l) 317 + { 318 + return l->max_win; 320 319 } 321 320 322 321 int tipc_link_prio(struct tipc_link *l) ··· 447 436 * @net_plane: network plane (A,B,c..) this link belongs to 448 437 * @mtu: mtu to be advertised by link 449 438 * @priority: priority to be used by link 450 - * @window: send window to be used by link 439 + * @min_win: minimal send window to be used by link 440 + * @max_win: maximal send window to be used by link 451 441 * @session: session to be used by link 452 442 * @ownnode: identity of own node 453 443 * @peer: node id of peer node ··· 463 451 */ 464 452 bool tipc_link_create(struct net *net, char *if_name, int bearer_id, 465 453 int tolerance, char net_plane, u32 mtu, int priority, 466 - int window, u32 session, u32 self, 454 + u32 min_win, u32 max_win, u32 session, u32 self, 467 455 u32 peer, u8 *peer_id, u16 peer_caps, 468 456 struct tipc_link *bc_sndlink, 469 457 struct tipc_link *bc_rcvlink, ··· 507 495 l->advertised_mtu = mtu; 508 496 l->mtu = mtu; 509 497 l->priority = priority; 510 - tipc_link_set_queue_limits(l, window); 498 + tipc_link_set_queue_limits(l, min_win, max_win); 511 499 l->ackers = 1; 512 500 l->bc_sndlink = bc_sndlink; 513 501 l->bc_rcvlink = bc_rcvlink; ··· 535 523 * Returns true if link was created, otherwise false 536 524 */ 537 525 bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer, 538 - int mtu, int window, u16 peer_caps, 526 + int mtu, u32 min_win, u32 max_win, u16 peer_caps, 539 527 struct sk_buff_head *inputq, 540 528 struct sk_buff_head *namedq, 541 529 struct tipc_link *bc_sndlink, ··· 543 531 { 544 532 struct tipc_link *l; 545 533 546 - if (!tipc_link_create(net, "", MAX_BEARERS, 0, 'Z', mtu, 0, window, 547 - 0, ownnode, peer, NULL, peer_caps, bc_sndlink, 548 - NULL, inputq, namedq, link)) 534 + if (!tipc_link_create(net, "", MAX_BEARERS, 0, 'Z', mtu, 0, min_win, 535 + max_win, 0, ownnode, peer, NULL, peer_caps, 536 + bc_sndlink, NULL, inputq, namedq, link)) 549 537 return false; 550 538 551 539 l = *link; ··· 784 772 return (l->silent_intv_cnt + 2 > l->abort_limit); 785 773 } 786 774 775 + static int tipc_link_bc_retrans(struct tipc_link *l, struct tipc_link *r, 776 + u16 from, u16 to, struct sk_buff_head *xmitq); 787 777 /* tipc_link_timeout - perform periodic task as instructed from node timeout 788 778 */ 789 779 int tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq) ··· 818 804 probe |= l->silent_intv_cnt; 819 805 if (probe || mstate->monitoring) 820 806 l->silent_intv_cnt++; 807 + if (l->snd_nxt == l->checkpoint) { 808 + tipc_link_update_cwin(l, 0, 0); 809 + probe = true; 810 + } 811 + l->checkpoint = l->snd_nxt; 821 812 break; 822 813 case LINK_RESET: 823 814 setup = l->rst_cnt++ <= 4; ··· 978 959 int pkt_cnt = skb_queue_len(list); 979 960 int imp = msg_importance(hdr); 980 961 unsigned int mss = tipc_link_mss(l); 981 - unsigned int maxwin = l->window; 962 + unsigned int cwin = l->window; 982 963 unsigned int mtu = l->mtu; 983 964 bool new_bundle; 984 965 int rc = 0; ··· 1007 988 1008 989 /* Prepare each packet for sending, and add to relevant queue: */ 1009 990 while ((skb = __skb_dequeue(list))) { 1010 - if (likely(skb_queue_len(transmq) < maxwin)) { 991 + if (likely(skb_queue_len(transmq) < cwin)) { 1011 992 hdr = buf_msg(skb); 1012 993 msg_set_seqno(hdr, seqno); 1013 994 msg_set_ack(hdr, ack); ··· 1054 1035 return rc; 1055 1036 } 1056 1037 1038 + static void tipc_link_update_cwin(struct tipc_link *l, int released, 1039 + bool retransmitted) 1040 + { 1041 + int bklog_len = skb_queue_len(&l->backlogq); 1042 + struct sk_buff_head *txq = &l->transmq; 1043 + int txq_len = skb_queue_len(txq); 1044 + u16 cwin = l->window; 1045 + 1046 + /* Enter fast recovery */ 1047 + if (unlikely(retransmitted)) { 1048 + l->ssthresh = max_t(u16, l->window / 2, 300); 1049 + l->window = l->ssthresh; 1050 + return; 1051 + } 1052 + /* Enter slow start */ 1053 + if (unlikely(!released)) { 1054 + l->ssthresh = max_t(u16, l->window / 2, 300); 1055 + l->window = l->min_win; 1056 + return; 1057 + } 1058 + /* Don't increase window if no pressure on the transmit queue */ 1059 + if (txq_len + bklog_len < cwin) 1060 + return; 1061 + 1062 + /* Don't increase window if there are holes the transmit queue */ 1063 + if (txq_len && l->snd_nxt - buf_seqno(skb_peek(txq)) != txq_len) 1064 + return; 1065 + 1066 + l->cong_acks += released; 1067 + 1068 + /* Slow start */ 1069 + if (cwin <= l->ssthresh) { 1070 + l->window = min_t(u16, cwin + released, l->max_win); 1071 + return; 1072 + } 1073 + /* Congestion avoidance */ 1074 + if (l->cong_acks < cwin) 1075 + return; 1076 + l->window = min_t(u16, ++cwin, l->max_win); 1077 + l->cong_acks = 0; 1078 + } 1079 + 1057 1080 static void tipc_link_advance_backlog(struct tipc_link *l, 1058 1081 struct sk_buff_head *xmitq) 1059 1082 { 1060 - struct sk_buff *skb, *_skb; 1061 - struct tipc_msg *hdr; 1062 - u16 seqno = l->snd_nxt; 1063 - u16 ack = l->rcv_nxt - 1; 1064 1083 u16 bc_ack = l->bc_rcvlink->rcv_nxt - 1; 1084 + struct sk_buff_head *txq = &l->transmq; 1085 + struct sk_buff *skb, *_skb; 1086 + u16 ack = l->rcv_nxt - 1; 1087 + u16 seqno = l->snd_nxt; 1088 + struct tipc_msg *hdr; 1089 + u16 cwin = l->window; 1065 1090 u32 imp; 1066 1091 1067 - while (skb_queue_len(&l->transmq) < l->window) { 1092 + while (skb_queue_len(txq) < cwin) { 1068 1093 skb = skb_peek(&l->backlogq); 1069 1094 if (!skb) 1070 1095 break; ··· 1204 1141 struct sk_buff *_skb, *skb = skb_peek(&l->transmq); 1205 1142 u16 bc_ack = l->bc_rcvlink->rcv_nxt - 1; 1206 1143 u16 ack = l->rcv_nxt - 1; 1144 + int retransmitted = 0; 1207 1145 struct tipc_msg *hdr; 1208 1146 int rc = 0; 1209 1147 ··· 1224 1160 continue; 1225 1161 if (more(msg_seqno(hdr), to)) 1226 1162 break; 1227 - 1228 1163 if (time_before(jiffies, TIPC_SKB_CB(skb)->nxt_retr)) 1229 1164 continue; 1230 1165 TIPC_SKB_CB(skb)->nxt_retr = TIPC_BC_RETR_LIM; ··· 1236 1173 _skb->priority = TC_PRIO_CONTROL; 1237 1174 __skb_queue_tail(xmitq, _skb); 1238 1175 l->stats.retransmitted++; 1239 - 1176 + retransmitted++; 1240 1177 /* Increase actual retrans counter & mark first time */ 1241 1178 if (!TIPC_SKB_CB(skb)->retr_cnt++) 1242 1179 TIPC_SKB_CB(skb)->retr_stamp = jiffies; 1243 1180 } 1181 + tipc_link_update_cwin(l, 0, retransmitted); 1244 1182 return 0; 1245 1183 } 1246 1184 ··· 1402 1338 return rc; 1403 1339 } 1404 1340 1405 - static bool tipc_link_release_pkts(struct tipc_link *l, u16 acked) 1341 + static int tipc_link_release_pkts(struct tipc_link *l, u16 acked) 1406 1342 { 1407 - bool released = false; 1343 + int released = 0; 1408 1344 struct sk_buff *skb, *tmp; 1409 1345 1410 1346 skb_queue_walk_safe(&l->transmq, skb, tmp) { ··· 1412 1348 break; 1413 1349 __skb_unlink(skb, &l->transmq); 1414 1350 kfree_skb(skb); 1415 - released = true; 1351 + released++; 1416 1352 } 1417 1353 return released; 1418 1354 } ··· 1481 1417 struct sk_buff *skb, *_skb, *tmp; 1482 1418 struct tipc_msg *hdr; 1483 1419 u16 bc_ack = l->bc_rcvlink->rcv_nxt - 1; 1420 + bool retransmitted = false; 1484 1421 u16 ack = l->rcv_nxt - 1; 1485 1422 bool passed = false; 1423 + u16 released = 0; 1486 1424 u16 seqno, n = 0; 1487 1425 int rc = 0; 1488 1426 ··· 1496 1430 /* release skb */ 1497 1431 __skb_unlink(skb, &l->transmq); 1498 1432 kfree_skb(skb); 1433 + released++; 1499 1434 } else if (less_eq(seqno, acked + gap)) { 1500 1435 /* First, check if repeated retrans failures occurs? */ 1501 1436 if (!passed && link_retransmit_failure(l, l, &rc)) ··· 1516 1449 _skb->priority = TC_PRIO_CONTROL; 1517 1450 __skb_queue_tail(xmitq, _skb); 1518 1451 l->stats.retransmitted++; 1519 - 1452 + retransmitted = true; 1520 1453 /* Increase actual retrans counter & mark first time */ 1521 1454 if (!TIPC_SKB_CB(skb)->retr_cnt++) 1522 1455 TIPC_SKB_CB(skb)->retr_stamp = jiffies; ··· 1530 1463 goto next_gap_ack; 1531 1464 } 1532 1465 } 1533 - 1466 + if (released || retransmitted) 1467 + tipc_link_update_cwin(l, released, retransmitted); 1468 + if (released) 1469 + tipc_link_advance_backlog(l, xmitq); 1534 1470 return 0; 1535 1471 } 1536 1472 ··· 1557 1487 l->snd_nxt = l->rcv_nxt; 1558 1488 return TIPC_LINK_SND_STATE; 1559 1489 } 1560 - 1561 1490 /* Unicast ACK */ 1562 1491 l->rcv_unacked = 0; 1563 1492 l->stats.sent_acks++; ··· 1622 1553 struct sk_buff_head *defq = &l->deferdq; 1623 1554 struct tipc_msg *hdr = buf_msg(skb); 1624 1555 u16 seqno, rcv_nxt, win_lim; 1556 + int released = 0; 1625 1557 int rc = 0; 1626 1558 1627 1559 /* Verify and update link state */ ··· 1641 1571 if (unlikely(!link_is_up(l))) { 1642 1572 if (l->state == LINK_ESTABLISHING) 1643 1573 rc = TIPC_LINK_UP_EVT; 1644 - goto drop; 1574 + kfree_skb(skb); 1575 + break; 1645 1576 } 1646 1577 1647 1578 /* Drop if outside receive window */ 1648 1579 if (unlikely(less(seqno, rcv_nxt) || more(seqno, win_lim))) { 1649 1580 l->stats.duplicates++; 1650 - goto drop; 1581 + kfree_skb(skb); 1582 + break; 1651 1583 } 1652 - 1653 - /* Forward queues and wake up waiting users */ 1654 - if (likely(tipc_link_release_pkts(l, msg_ack(hdr)))) { 1655 - tipc_link_advance_backlog(l, xmitq); 1656 - if (unlikely(!skb_queue_empty(&l->wakeupq))) 1657 - link_prepare_wakeup(l); 1658 - } 1584 + released += tipc_link_release_pkts(l, msg_ack(hdr)); 1659 1585 1660 1586 /* Defer delivery if sequence gap */ 1661 1587 if (unlikely(seqno != rcv_nxt)) { ··· 1674 1608 break; 1675 1609 } while ((skb = __tipc_skb_dequeue(defq, l->rcv_nxt))); 1676 1610 1677 - return rc; 1678 - drop: 1679 - kfree_skb(skb); 1611 + /* Forward queues and wake up waiting users */ 1612 + if (released) { 1613 + tipc_link_update_cwin(l, released, 0); 1614 + tipc_link_advance_backlog(l, xmitq); 1615 + if (unlikely(!skb_queue_empty(&l->wakeupq))) 1616 + link_prepare_wakeup(l); 1617 + } 1680 1618 return rc; 1681 1619 } 1682 1620 ··· 2154 2084 !tipc_link_is_synching(l) && 2155 2085 skb_queue_empty(&l->deferdq)) 2156 2086 rcvgap = peers_snd_nxt - l->rcv_nxt; 2157 - 2158 2087 if (rcvgap || reply) 2159 2088 tipc_link_build_proto_msg(l, STATE_MSG, 0, reply, 2160 2089 rcvgap, 0, 0, xmitq); 2161 - rc |= tipc_link_advance_transmq(l, ack, gap, ga, xmitq); 2162 2090 2163 - /* If NACK, retransmit will now start at right position */ 2091 + rc |= tipc_link_advance_transmq(l, ack, gap, ga, xmitq); 2164 2092 if (gap) 2165 2093 l->stats.recv_nacks++; 2166 - 2167 - tipc_link_advance_backlog(l, xmitq); 2168 2094 if (unlikely(!skb_queue_empty(&l->wakeupq))) 2169 2095 link_prepare_wakeup(l); 2170 2096 } ··· 2379 2313 return 0; 2380 2314 } 2381 2315 2382 - void tipc_link_set_queue_limits(struct tipc_link *l, u32 win) 2316 + void tipc_link_set_queue_limits(struct tipc_link *l, u32 min_win, u32 max_win) 2383 2317 { 2384 2318 int max_bulk = TIPC_MAX_PUBL / (l->mtu / ITEM_SIZE); 2385 2319 2386 - l->window = win; 2387 - l->backlog[TIPC_LOW_IMPORTANCE].limit = max_t(u16, 50, win); 2388 - l->backlog[TIPC_MEDIUM_IMPORTANCE].limit = max_t(u16, 100, win * 2); 2389 - l->backlog[TIPC_HIGH_IMPORTANCE].limit = max_t(u16, 150, win * 3); 2390 - l->backlog[TIPC_CRITICAL_IMPORTANCE].limit = max_t(u16, 200, win * 4); 2320 + l->min_win = min_win; 2321 + l->ssthresh = max_win; 2322 + l->max_win = max_win; 2323 + l->window = min_win; 2324 + l->backlog[TIPC_LOW_IMPORTANCE].limit = min_win * 2; 2325 + l->backlog[TIPC_MEDIUM_IMPORTANCE].limit = min_win * 4; 2326 + l->backlog[TIPC_HIGH_IMPORTANCE].limit = min_win * 6; 2327 + l->backlog[TIPC_CRITICAL_IMPORTANCE].limit = min_win * 8; 2391 2328 l->backlog[TIPC_SYSTEM_IMPORTANCE].limit = max_bulk; 2392 2329 } 2393 2330 ··· 2443 2374 } 2444 2375 2445 2376 if (props[TIPC_NLA_PROP_WIN]) { 2446 - u32 win; 2377 + u32 max_win; 2447 2378 2448 - win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 2449 - if ((win < TIPC_MIN_LINK_WIN) || (win > TIPC_MAX_LINK_WIN)) 2379 + max_win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 2380 + if (max_win < TIPC_DEF_LINK_WIN || max_win > TIPC_MAX_LINK_WIN) 2450 2381 return -EINVAL; 2451 2382 } 2452 2383 ··· 2682 2613 prop = nla_nest_start_noflag(msg->skb, TIPC_NLA_LINK_PROP); 2683 2614 if (!prop) 2684 2615 goto attr_msg_full; 2685 - if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, bcl->window)) 2616 + if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, bcl->max_win)) 2686 2617 goto prop_msg_full; 2687 2618 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_BROADCAST, bc_mode)) 2688 2619 goto prop_msg_full;
+5 -4
net/tipc/link.h
··· 73 73 74 74 bool tipc_link_create(struct net *net, char *if_name, int bearer_id, 75 75 int tolerance, char net_plane, u32 mtu, int priority, 76 - int window, u32 session, u32 ownnode, 76 + u32 min_win, u32 max_win, u32 session, u32 ownnode, 77 77 u32 peer, u8 *peer_id, u16 peer_caps, 78 78 struct tipc_link *bc_sndlink, 79 79 struct tipc_link *bc_rcvlink, ··· 81 81 struct sk_buff_head *namedq, 82 82 struct tipc_link **link); 83 83 bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer, 84 - int mtu, int window, u16 peer_caps, 84 + int mtu, u32 min_win, u32 max_win, u16 peer_caps, 85 85 struct sk_buff_head *inputq, 86 86 struct sk_buff_head *namedq, 87 87 struct tipc_link *bc_sndlink, ··· 115 115 u32 tipc_link_state(struct tipc_link *l); 116 116 char tipc_link_plane(struct tipc_link *l); 117 117 int tipc_link_prio(struct tipc_link *l); 118 - int tipc_link_window(struct tipc_link *l); 118 + int tipc_link_min_win(struct tipc_link *l); 119 + int tipc_link_max_win(struct tipc_link *l); 119 120 void tipc_link_update_caps(struct tipc_link *l, u16 capabilities); 120 121 bool tipc_link_validate_msg(struct tipc_link *l, struct tipc_msg *hdr); 121 122 unsigned long tipc_link_tolerance(struct tipc_link *l); ··· 125 124 void tipc_link_set_prio(struct tipc_link *l, u32 prio, 126 125 struct sk_buff_head *xmitq); 127 126 void tipc_link_set_abort_limit(struct tipc_link *l, u32 limit); 128 - void tipc_link_set_queue_limits(struct tipc_link *l, u32 window); 127 + void tipc_link_set_queue_limits(struct tipc_link *l, u32 min_win, u32 max_win); 129 128 int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg, 130 129 struct tipc_link *link, int nlflags); 131 130 int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]);
+9 -7
net/tipc/node.c
··· 1139 1139 snd_l = tipc_bc_sndlink(net); 1140 1140 if (!tipc_link_bc_create(net, tipc_own_addr(net), 1141 1141 addr, U16_MAX, 1142 - tipc_link_window(snd_l), 1142 + tipc_link_min_win(snd_l), 1143 + tipc_link_max_win(snd_l), 1143 1144 n->capabilities, 1144 1145 &n->bc_entry.inputq1, 1145 1146 &n->bc_entry.namedq, snd_l, ··· 1234 1233 get_random_bytes(&session, sizeof(u16)); 1235 1234 if (!tipc_link_create(net, if_name, b->identity, b->tolerance, 1236 1235 b->net_plane, b->mtu, b->priority, 1237 - b->window, session, 1236 + b->min_win, b->max_win, session, 1238 1237 tipc_own_addr(net), addr, peer_id, 1239 1238 n->capabilities, 1240 1239 tipc_bc_sndlink(n->net), n->bc_entry.link, ··· 2361 2360 if (attrs[TIPC_NLA_LINK_PROP]) { 2362 2361 struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; 2363 2362 2364 - err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_LINK_PROP], 2365 - props); 2363 + err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_LINK_PROP], props); 2366 2364 if (err) { 2367 2365 res = err; 2368 2366 goto out; ··· 2380 2380 tipc_link_set_prio(link, prio, &xmitq); 2381 2381 } 2382 2382 if (props[TIPC_NLA_PROP_WIN]) { 2383 - u32 win; 2383 + u32 max_win; 2384 2384 2385 - win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 2386 - tipc_link_set_queue_limits(link, win); 2385 + max_win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 2386 + tipc_link_set_queue_limits(link, 2387 + tipc_link_min_win(link), 2388 + max_win); 2387 2389 } 2388 2390 } 2389 2391
+2 -1
net/tipc/udp_media.c
··· 828 828 .msg2addr = tipc_udp_msg2addr, 829 829 .priority = TIPC_DEF_LINK_PRI, 830 830 .tolerance = TIPC_DEF_LINK_TOL, 831 - .window = TIPC_DEF_LINK_WIN, 831 + .min_win = TIPC_DEF_LINK_WIN, 832 + .max_win = TIPC_DEF_LINK_WIN, 832 833 .mtu = TIPC_DEF_LINK_UDP_MTU, 833 834 .type_id = TIPC_MEDIA_TYPE_UDP, 834 835 .hwaddr_len = 0,