History

Merge branch 'mptcp-misc-fixes-for-v7-3-rc1'

Matthieu Baerts says: ==================== mptcp: misc fixes for v7.3-rc1 Here are various unrelated fixes: - Patch 1: Do not reschedule the RTX timer for sockets that fell back to TCP. A fix for v5.7. - Patch 2: Avoid copying thmac which will not be used and could be uninitialised. A fix for v5.7. - Patch 3: Re-set the request backup flag when SYN cookies are used. A fix for v5.9. - Patch 4: Drop pending ADD_ADDR when removing ID0, and avoid a WARN. A fix for v5.13. - Patch 5: Handle invalid suboptions where the checksum is requested in the MP_CAPABLE 4th ACK with data, but not added in the option. A fix for v5.14. - Patch 6: Prevent a race between mptcp_disconnect() and the retransmit timer. A fix for v5.17. - Patch 7: Fix a use-after-free in the selftests that could lead to false positive. A fix for v5.17. - Patch 8: Limit new addresses with the userspace PM to avoid an address ID overflow. A fix for v5.19. - Patch 9: Reset the ADD_ADDR retransmission counter when the timer is reused. A fix for v5.19. - Patch 10: Remove unneeded and confusing READ_ONCE() annotations. A fix for v6.13. - Patches 11-12: Get nstat counters for the current test, not since the creation of the netns. A fix for v6.19. - Patch 13: Fix an uninit-value in mptcp_write_data_fin for a corner case now that only a part of the tcp_out_options struct is reset. A fix for v7.1. - Patches 14-15: Two follow-up patches addressing minor comments discovered after the human review. A fix for v7.3-rc1. ====================

Jakub Kicinski committed 2 months ago

Commit 9a1599e2 parents 5be081b f01b82710 files · +78 −36Browse files

Unified · Split

10 files
  1. net/mptcp/options.c +5 −3
  2. net/mptcp/pm.c +1 −1
  3. net/mptcp/pm_kernel.c +8 −0
  4. net/mptcp/pm_userspace.c +14 −4
  5. net/mptcp/protocol.c +27 −14
  6. net/mptcp/protocol.h +1 −0
  7. net/mptcp/subflow.c +0 −1
  8. net/mptcp/syncookies.c +4 −1
  9. tools/testing/selftests/net/mptcp/mptcp_connect.c +3 −1
  10. tools/testing/selftests/net/mptcp/mptcp_lib.sh +15 −11
net/mptcp/options.c+5−3
@@ -93,7 +93,8 @@ static void mptcp_parse_option(const struct sk_buff *skb, · 92 unmodified lines
93 * In other words, the only way for checksums not to be used93 * In other words, the only way for checksums not to be used
94 * is if both hosts in their SYNs set A=0."94 * is if both hosts in their SYNs set A=0."
95 */95 */
96 if (flags & MPTCP_CAP_CHECKSUM_REQD)96 if ((flags & MPTCP_CAP_CHECKSUM_REQD) &&
97 opsize < TCPOLEN_MPTCP_MPC_ACK_DATA)
97 mp_opt->suboptions |= OPTION_MPTCP_CSUMREQD;98 mp_opt->suboptions |= OPTION_MPTCP_CSUMREQD;
98 99
99 mp_opt->deny_join_id0 = !!(flags & MPTCP_CAP_DENY_JOIN_ID0);100 mp_opt->deny_join_id0 = !!(flags & MPTCP_CAP_DENY_JOIN_ID0);
@@ -529,7 +530,7 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb, · 429 unmodified lines
529 return false;530 return false;
530 531
531 /* MPC/MPJ needed only on 3rd ack packet, DATA_FIN and TCP shutdown take precedence */532 /* MPC/MPJ needed only on 3rd ack packet, DATA_FIN and TCP shutdown take precedence */
532 if (READ_ONCE(subflow->fully_established) || snd_data_fin_enable ||533 if (subflow->fully_established || snd_data_fin_enable ||
533 subflow->snd_isn != TCP_SKB_CB(skb)->seq ||534 subflow->snd_isn != TCP_SKB_CB(skb)->seq ||
534 sk->sk_state != TCP_ESTABLISHED)535 sk->sk_state != TCP_ESTABLISHED)
535 return false;536 return false;
@@ -611,6 +612,7 @@ static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow, · 75 unmodified lines
611 ext->data_seq = data_fin_tx_seq;612 ext->data_seq = data_fin_tx_seq;
612 ext->subflow_seq = 0;613 ext->subflow_seq = 0;
613 ext->data_len = 1;614 ext->data_len = 1;
615 ext->csum = 0;
614 } else if (ext->data_seq + ext->data_len == data_fin_tx_seq) {616 } else if (ext->data_seq + ext->data_len == data_fin_tx_seq) {
615 /* If there's an existing DSS mapping and it is the617 /* If there's an existing DSS mapping and it is the
616 * final mapping, DATA_FIN consumes 1 additional byte of618 * final mapping, DATA_FIN consumes 1 additional byte of
@@ -980,7 +982,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk, · 363 unmodified lines
980 /* here we can process OoO, in-window pkts, only in-sequence 4th ack982 /* here we can process OoO, in-window pkts, only in-sequence 4th ack
981 * will make the subflow fully established983 * will make the subflow fully established
982 */984 */
983 if (likely(READ_ONCE(subflow->fully_established))) {985 if (likely(subflow->fully_established)) {
984 /* on passive sockets, check for 3rd ack retransmission986 /* on passive sockets, check for 3rd ack retransmission
985 * note that msk is always set by subflow_syn_recv_sock()987 * note that msk is always set by subflow_syn_recv_sock()
986 * for mp_join subflows988 * for mp_join subflows
net/mptcp/pm.c+1−1
@@ -462,10 +462,10 @@ bool mptcp_pm_announced_alloc(struct mptcp_sock *msk, · 461 unmodified lines
462 462
463 add_entry->addr = *addr;463 add_entry->addr = *addr;
464 add_entry->sock = msk;464 add_entry->sock = msk;
465 add_entry->retrans_times = 0;
466 465
467 timer_setup(&add_entry->timer, mptcp_pm_add_addr_timer, 0);466 timer_setup(&add_entry->timer, mptcp_pm_add_addr_timer, 0);
468reset_timer:467reset_timer:
468 add_entry->retrans_times = 0;
469 add_entry->timer_done = false;469 add_entry->timer_done = false;
470 timeout = mptcp_adjust_add_addr_timeout(msk);470 timeout = mptcp_adjust_add_addr_timeout(msk);
471 if (timeout)471 if (timeout)
net/mptcp/pm_kernel.c+8−0
@@ -1137,6 +1137,8 @@ static int mptcp_nl_remove_id_zero_address(struct net *net, · 1136 unmodified lines
1137 while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) {1137 while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) {
1138 struct sock *sk = (struct sock *)msk;1138 struct sock *sk = (struct sock *)msk;
1139 struct mptcp_addr_info msk_local;1139 struct mptcp_addr_info msk_local;
1140 struct mptcp_addr_info anno_addr;
1141 bool announced;
1140 1142
1141 if (list_empty(&msk->conn_list) || mptcp_pm_is_userspace(msk))1143 if (list_empty(&msk->conn_list) || mptcp_pm_is_userspace(msk))
1142 goto next;1144 goto next;
@@ -1146,7 +1148,13 @@ static int mptcp_nl_remove_id_zero_address(struct net *net, · 3 unmodified lines
1146 goto next;1148 goto next;
1147 1149
1148 lock_sock(sk);1150 lock_sock(sk);
1151 /* Drop a possibly pending ADD_ADDR for this address. */
1152 anno_addr = msk_local;
1153 anno_addr.port = 0;
1154 announced = mptcp_pm_announced_remove(msk, &anno_addr);
1149 spin_lock_bh(&msk->pm.lock);1155 spin_lock_bh(&msk->pm.lock);
1156 if (announced)
1157 msk->pm.add_addr_signaled--;
1150 mptcp_pm_remove_addr(msk, &list);1158 mptcp_pm_remove_addr(msk, &list);
1151 mptcp_pm_rm_subflow(msk, &list);1159 mptcp_pm_rm_subflow(msk, &list);
1152 __mark_subflow_endp_available(msk, 0);1160 __mark_subflow_endp_available(msk, 0);
net/mptcp/pm_userspace.c+14−4
@@ -69,6 +69,19 @@ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk, · 68 unmodified lines
69 }69 }
70 70
71 if (!addr_match && !id_match) {71 if (!addr_match && !id_match) {
72 unsigned int id;
73
74 if (!entry->addr.id && needs_id) {
75 id = find_next_zero_bit(id_bitmap,
76 MPTCP_PM_MAX_ADDR_ID + 1, 1);
77 if (id > MPTCP_PM_MAX_ADDR_ID) {
78 ret = -ENOSPC;
79 goto append_err;
80 }
81 } else {
82 id = entry->addr.id;
83 }
84
72 /* Memory for the entry is allocated from the85 /* Memory for the entry is allocated from the
73 * sock option buffer.86 * sock option buffer.
74 */87 */
@@ -78,10 +91,7 @@ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk, · 3 unmodified lines
78 goto append_err;91 goto append_err;
79 }92 }
80 93
81 if (!e->addr.id && needs_id)94 e->addr.id = id;
82 e->addr.id = find_next_zero_bit(id_bitmap,
83 MPTCP_PM_MAX_ADDR_ID + 1,
84 1);
85 list_add_tail_rcu(&e->list, &msk->pm.userspace_pm_local_addr_list);95 list_add_tail_rcu(&e->list, &msk->pm.userspace_pm_local_addr_list);
86 msk->pm.local_addr_used++;96 msk->pm.local_addr_used++;
87 ret = e->addr.id;97 ret = e->addr.id;
net/mptcp/protocol.c+27−14
@@ -95,6 +95,7 @@ bool __mptcp_try_fallback(struct mptcp_sock *msk, int fb_mib) · 94 unmodified lines
95 95
96 msk->allow_subflows = false;96 msk->allow_subflows = false;
97 set_bit(MPTCP_FALLBACK_DONE, &msk->flags);97 set_bit(MPTCP_FALLBACK_DONE, &msk->flags);
98 clear_bit(MPTCP_RTX_ENABLED, &msk->flags);
98 __MPTCP_INC_STATS(net, fb_mib);99 __MPTCP_INC_STATS(net, fb_mib);
99 spin_unlock_bh(&msk->fallback_lock);100 spin_unlock_bh(&msk->fallback_lock);
100 return true;101 return true;
@@ -288,8 +289,8 @@ static void mptcp_prune_ofo_queue(struct sock *sk, · 187 unmodified lines
288 */289 */
289static bool mptcp_can_ingest(const struct sock *sk)290static bool mptcp_can_ingest(const struct sock *sk)
290{291{
291 return unlikely(sk_rmem_alloc_get(sk) <= READ_ONCE(sk->sk_rcvbuf)) ||292 return likely(sk_rmem_alloc_get(sk) <= READ_ONCE(sk->sk_rcvbuf)) ||
292 __mptcp_check_fallback(mptcp_sk(sk));293 __mptcp_check_fallback(mptcp_sk(sk));
293}294}
294 295
295static bool mptcp_try_rmem_schedule(struct sock *sk, const struct sk_buff *skb)296static bool mptcp_try_rmem_schedule(struct sock *sk, const struct sk_buff *skb)
@@ -312,12 +313,6 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk, struct sk_buff *skb) · 16 unmodified lines
312 u64 seq, end_seq, max_seq;313 u64 seq, end_seq, max_seq;
313 struct sk_buff *skb1;314 struct sk_buff *skb1;
314 315
315 if (!mptcp_try_rmem_schedule(sk, skb)) {
316 MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED);
317 mptcp_drop(sk, skb);
318 return;
319 }
320
321 seq = MPTCP_SKB_CB(skb)->map_seq;316 seq = MPTCP_SKB_CB(skb)->map_seq;
322 end_seq = MPTCP_SKB_CB(skb)->end_seq;317 end_seq = MPTCP_SKB_CB(skb)->end_seq;
323 max_seq = atomic64_read(&msk->rcv_wnd_sent);318 max_seq = atomic64_read(&msk->rcv_wnd_sent);
@@ -334,6 +329,12 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk, struct sk_buff *skb) · 10 unmodified lines
334 return;329 return;
335 }330 }
336 331
332 if (!mptcp_try_rmem_schedule(sk, skb)) {
333 MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED);
334 mptcp_drop(sk, skb);
335 return;
336 }
337
337 p = &msk->out_of_order_queue.rb_node;338 p = &msk->out_of_order_queue.rb_node;
338 MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOQUEUE);339 MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOQUEUE);
339 if (RB_EMPTY_ROOT(&msk->out_of_order_queue)) {340 if (RB_EMPTY_ROOT(&msk->out_of_order_queue)) {
@@ -1084,13 +1085,14 @@ static bool mptcp_rtx_timer_pending(struct sock *sk) · 744 unmodified lines
1084 1085
1085static void mptcp_reset_rtx_timer(struct sock *sk)1086static void mptcp_reset_rtx_timer(struct sock *sk)
1086{1087{
1088 struct mptcp_sock *msk = mptcp_sk(sk);
1087 unsigned long tout;1089 unsigned long tout;
1088 1090
1089 /* prevent rescheduling on close */1091 /* Prevent rescheduling on close and in case of fallback. */
1090 if (unlikely(inet_sk_state_load(sk) == TCP_CLOSE))1092 if (!test_bit(MPTCP_RTX_ENABLED, &msk->flags))
1091 return;1093 return;
1092 1094
1093 tout = mptcp_sk(sk)->timer_ival;1095 tout = msk->timer_ival;
1094 sk_reset_timer(sk, &sk->mptcp_retransmit_timer, jiffies + tout);1096 sk_reset_timer(sk, &sk->mptcp_retransmit_timer, jiffies + tout);
1095}1097}
1096 1098
@@ -3323,6 +3325,9 @@ void mptcp_set_state(struct sock *sk, int state) · 2226 unmodified lines
3323 * transition from TCP_SYN_RECV to TCP_CLOSE_WAIT.3325 * transition from TCP_SYN_RECV to TCP_CLOSE_WAIT.
3324 */3326 */
3325 break;3327 break;
3328 case TCP_CLOSE:
3329 clear_bit(MPTCP_RTX_ENABLED, &mptcp_sk(sk)->flags);
3330 fallthrough;
3326 default:3331 default:
3327 if (oldstate == TCP_ESTABLISHED || oldstate == TCP_CLOSE_WAIT)3332 if (oldstate == TCP_ESTABLISHED || oldstate == TCP_CLOSE_WAIT)
3328 MPTCP_DEC_STATS(sock_net(sk), MPTCP_MIB_CURRESTAB);3333 MPTCP_DEC_STATS(sock_net(sk), MPTCP_MIB_CURRESTAB);
@@ -3583,6 +3588,7 @@ static void mptcp_destroy_common(struct mptcp_sock *msk) · 254 unmodified lines
3583 3588
3584static int mptcp_disconnect(struct sock *sk, int flags)3589static int mptcp_disconnect(struct sock *sk, int flags)
3585{3590{
3591 struct inet_connection_sock *icsk = inet_csk(sk);
3586 struct mptcp_sock *msk = mptcp_sk(sk);3592 struct mptcp_sock *msk = mptcp_sk(sk);
3587 3593
3588 /* We are on the fastopen error path. We can't call straight into the3594 /* We are on the fastopen error path. We can't call straight into the
@@ -3595,8 +3601,13 @@ static int mptcp_disconnect(struct sock *sk, int flags) · 6 unmodified lines
3595 mptcp_check_listen_stop(sk);3601 mptcp_check_listen_stop(sk);
3596 mptcp_set_state(sk, TCP_CLOSE);3602 mptcp_set_state(sk, TCP_CLOSE);
3597 3603
3598 mptcp_stop_rtx_timer(sk);3604 /* The later subflow close can not kick again the tout timer,
3599 mptcp_stop_tout_timer(sk);3605 * as the msk is already in closed status.
3606 */
3607 msk->timer_ival = icsk->icsk_rto_min;
3608 sk_stop_timer_sync(sk, &sk->mptcp_retransmit_timer);
3609 icsk->icsk_mtup.probe_timestamp = 0;
3610 sk_stop_timer_sync(sk, &icsk->mptcp_tout_timer);
3600 3611
3601 mptcp_pm_connection_closed(msk);3612 mptcp_pm_connection_closed(msk);
3602 3613
@@ -3875,7 +3886,7 @@ static void schedule_3rdack_retransmission(struct sock *ssk) · 272 unmodified lines
3875 struct tcp_sock *tp = tcp_sk(ssk);3886 struct tcp_sock *tp = tcp_sk(ssk);
3876 unsigned long timeout;3887 unsigned long timeout;
3877 3888
3878 if (READ_ONCE(mptcp_subflow_ctx(ssk)->fully_established))3889 if (mptcp_subflow_ctx(ssk)->fully_established)
3879 return;3890 return;
3880 3891
3881 /* reschedule with a timeout above RTT, as we must look only for drop */3892 /* reschedule with a timeout above RTT, as we must look only for drop */
@@ -4141,6 +4152,7 @@ static int mptcp_connect(struct sock *sk, struct sockaddr_unsized *uaddr, · 259 unmodified lines
4141 if (IS_ERR(ssk))4152 if (IS_ERR(ssk))
4142 return PTR_ERR(ssk);4153 return PTR_ERR(ssk);
4143 4154
4155 set_bit(MPTCP_RTX_ENABLED, &msk->flags);
4144 mptcp_set_state(sk, TCP_SYN_SENT);4156 mptcp_set_state(sk, TCP_SYN_SENT);
4145 subflow = mptcp_subflow_ctx(ssk);4157 subflow = mptcp_subflow_ctx(ssk);
4146#ifdef CONFIG_TCP_MD5SIG4158#ifdef CONFIG_TCP_MD5SIG
@@ -4288,6 +4300,7 @@ static int mptcp_listen(struct socket *sock, int backlog) · 141 unmodified lines
4288 goto unlock;4300 goto unlock;
4289 }4301 }
4290 4302
4303 set_bit(MPTCP_RTX_ENABLED, &msk->flags);
4291 mptcp_set_state(sk, TCP_LISTEN);4304 mptcp_set_state(sk, TCP_LISTEN);
4292 sock_set_flag(sk, SOCK_RCU_FREE);4305 sock_set_flag(sk, SOCK_RCU_FREE);
4293 4306
net/mptcp/protocol.h+1−0
@@ -116,6 +116,7 @@ · 115 unmodified lines
116#define MPTCP_WORK_RTX 1116#define MPTCP_WORK_RTX 1
117#define MPTCP_FALLBACK_DONE 2117#define MPTCP_FALLBACK_DONE 2
118#define MPTCP_WORK_CLOSE_SUBFLOW 3118#define MPTCP_WORK_CLOSE_SUBFLOW 3
119#define MPTCP_RTX_ENABLED 4
119 120
120/* MPTCP socket release cb flags */121/* MPTCP socket release cb flags */
121#define MPTCP_PUSH_PENDING 1122#define MPTCP_PUSH_PENDING 1
net/mptcp/subflow.c+0−1
@@ -2084,7 +2084,6 @@ static void subflow_ulp_clone(const struct request_sock *req, · 2083 unmodified lines
2084 new_ctx->request_bkup = subflow_req->request_bkup;2084 new_ctx->request_bkup = subflow_req->request_bkup;
2085 WRITE_ONCE(new_ctx->remote_id, subflow_req->remote_id);2085 WRITE_ONCE(new_ctx->remote_id, subflow_req->remote_id);
2086 new_ctx->token = subflow_req->token;2086 new_ctx->token = subflow_req->token;
2087 new_ctx->thmac = subflow_req->thmac;
2088 2087
2089 /* the subflow req id is valid, fetched via subflow_check_req()2088 /* the subflow req id is valid, fetched via subflow_check_req()
2090 * and subflow_token_join_request()2089 * and subflow_token_join_request()
net/mptcp/syncookies.c+4−1
@@ -26,7 +26,8 @@ struct join_entry { · 25 unmodified lines
26 u32 local_nonce;26 u32 local_nonce;
27 u8 join_id;27 u8 join_id;
28 u8 local_id;28 u8 local_id;
29 u8 backup;29 u8 backup:1,
30 request_bkup:1;
30 u8 valid;31 u8 valid;
31};32};
32 33
@@ -63,6 +64,7 @@ static void mptcp_join_store_state(struct join_entry *entry, · 30 unmodified lines
63 entry->remote_nonce = subflow_req->remote_nonce;64 entry->remote_nonce = subflow_req->remote_nonce;
64 entry->local_nonce = subflow_req->local_nonce;65 entry->local_nonce = subflow_req->local_nonce;
65 entry->backup = subflow_req->backup;66 entry->backup = subflow_req->backup;
67 entry->request_bkup = subflow_req->request_bkup;
66 entry->join_id = subflow_req->remote_id;68 entry->join_id = subflow_req->remote_id;
67 entry->local_id = subflow_req->local_id;69 entry->local_id = subflow_req->local_id;
68 entry->valid = 1;70 entry->valid = 1;
@@ -117,6 +119,7 @@ bool mptcp_token_join_cookie_init_state(struct mptcp_subflow_request_sock *subfl · 48 unmodified lines
117 subflow_req->remote_nonce = e->remote_nonce;119 subflow_req->remote_nonce = e->remote_nonce;
118 subflow_req->local_nonce = e->local_nonce;120 subflow_req->local_nonce = e->local_nonce;
119 subflow_req->backup = e->backup;121 subflow_req->backup = e->backup;
122 subflow_req->request_bkup = e->request_bkup;
120 subflow_req->remote_id = e->join_id;123 subflow_req->remote_id = e->join_id;
121 subflow_req->local_id = e->local_id;124 subflow_req->local_id = e->local_id;
122 subflow_req->token = e->token;125 subflow_req->token = e->token;
tools/testing/selftests/net/mptcp/mptcp_connect.c+3−1
@@ -381,6 +381,9 @@ static int sock_connect_mptcp(const char * const remoteaddr, · 380 unmodified lines
381 381
382 hints.ai_family = pf;382 hints.ai_family = pf;
383 383
384 /* Keep the resolved address alive for the whole execution: it is
385 * used again when reconnecting, and will be released at exit time.
386 */
384 xgetaddrinfo(remoteaddr, port, &hints, &addr);387 xgetaddrinfo(remoteaddr, port, &hints, &addr);
385 for (a = addr; a; a = a->ai_next) {388 for (a = addr; a; a = a->ai_next) {
386 sock = socket(a->ai_family, a->ai_socktype, proto);389 sock = socket(a->ai_family, a->ai_socktype, proto);
@@ -421,7 +424,6 @@ static int sock_connect_mptcp(const char * const remoteaddr, · 34 unmodified lines
421 sock = -1;424 sock = -1;
422 }425 }
423 426
424 freeaddrinfo(addr);
425 if (sock != -1)427 if (sock != -1)
426 SOCK_TEST_TCPULP(sock, proto);428 SOCK_TEST_TCPULP(sock, proto);
427 return sock;429 return sock;
tools/testing/selftests/net/mptcp/mptcp_lib.sh+15−11
@@ -108,12 +108,14 @@ mptcp_lib_pr_info() { · 107 unmodified lines
108 108
109mptcp_lib_pr_nstat() {109mptcp_lib_pr_nstat() {
110 local ns="${1}"110 local ns="${1}"
111 local hist="/tmp/${ns}.out"111 local cache="/tmp/${ns}.out"
112 local hist="/tmp/${ns}.nstat"
112 113
113 if [ -f "${hist}" ]; then114 if [ -f "${cache}" ]; then
114 awk '$2 != 0 { print " "$0 }' "${hist}"115 awk '$2 != 0 { print " "$0 }' "${cache}"
115 else116 else
116 ip netns exec "${ns}" nstat -as | grep Tcp117 NSTAT_HISTORY="${hist}" ip netns exec "${ns}" nstat -s |
118 grep Tcp
117 fi119 fi
118}120}
119 121
@@ -414,19 +416,21 @@ mptcp_lib_nstat_get() { · 294 unmodified lines
414}416}
415 417
416# $1: ns, $2: MIB counter418# $1: ns, $2: MIB counter
417# Get the counter from the history (mptcp_lib_nstat_{init,get}()) if available.419# Get the counter from the cache (mptcp_lib_nstat_{init,get}()) if available.
418# If not, get the counter from nstat ignoring any history.420# If not, get the counter from nstat ignoring any cache, but using the history.
419mptcp_lib_get_counter() {421mptcp_lib_get_counter() {
420 local ns="${1}"422 local ns="${1}"
421 local counter="${2}"423 local counter="${2}"
422 local hist="/tmp/${ns}.out"424 local cache="/tmp/${ns}.out"
425 local hist="/tmp/${ns}.nstat"
423 local count426 local count
424 427
425 if [[ -s "${hist}" && "${counter}" == *"Tcp"* ]]; then428 if [[ -s "${cache}" && "${counter}" == *"Tcp"* ]]; then
426 count=$(awk "/^${counter} / {print \$2; exit}" "${hist}")429 count=$(awk "/^${counter} / {print \$2; exit}" "${cache}")
427 else430 else
428 count=$(ip netns exec "${ns}" nstat -asz "${counter}" |431 count=$(NSTAT_HISTORY="${hist}" ip netns exec "${ns}" \
429 awk 'NR==1 {next} {print $2}')432 nstat -sz "${counter}" |
433 awk 'NR==1 {next} {print $2}')
430 fi434 fi
431 if [ -z "${count}" ]; then435 if [ -z "${count}" ]; then
432 mptcp_lib_fail_if_expected_feature "${counter} counter"436 mptcp_lib_fail_if_expected_feature "${counter} counter"