1*e18b97bdSRandall Stewart /*-
2*e18b97bdSRandall Stewart * Copyright (c) 2024- Netflix, Inc.
3*e18b97bdSRandall Stewart *
4*e18b97bdSRandall Stewart * Redistribution and use in source and binary forms, with or without
5*e18b97bdSRandall Stewart * modification, are permitted provided that the following conditions
6*e18b97bdSRandall Stewart * are met:
7*e18b97bdSRandall Stewart * 1. Redistributions of source code must retain the above copyright
8*e18b97bdSRandall Stewart * notice, this list of conditions and the following disclaimer.
9*e18b97bdSRandall Stewart * 2. Redistributions in binary form must reproduce the above copyright
10*e18b97bdSRandall Stewart * notice, this list of conditions and the following disclaimer in the
11*e18b97bdSRandall Stewart * documentation and/or other materials provided with the distribution.
12*e18b97bdSRandall Stewart *
13*e18b97bdSRandall Stewart * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
14*e18b97bdSRandall Stewart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15*e18b97bdSRandall Stewart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16*e18b97bdSRandall Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
17*e18b97bdSRandall Stewart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18*e18b97bdSRandall Stewart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19*e18b97bdSRandall Stewart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20*e18b97bdSRandall Stewart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21*e18b97bdSRandall Stewart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22*e18b97bdSRandall Stewart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23*e18b97bdSRandall Stewart * SUCH DAMAGE.
24*e18b97bdSRandall Stewart *
25*e18b97bdSRandall Stewart */
26*e18b97bdSRandall Stewart
27*e18b97bdSRandall Stewart #include <sys/cdefs.h>
28*e18b97bdSRandall Stewart #include "opt_inet.h"
29*e18b97bdSRandall Stewart #include "opt_inet6.h"
30*e18b97bdSRandall Stewart #include "opt_ipsec.h"
31*e18b97bdSRandall Stewart #include "opt_ratelimit.h"
32*e18b97bdSRandall Stewart #include "opt_kern_tls.h"
33*e18b97bdSRandall Stewart #if defined(INET) || defined(INET6)
34*e18b97bdSRandall Stewart #include <sys/param.h>
35*e18b97bdSRandall Stewart #include <sys/arb.h>
36*e18b97bdSRandall Stewart #include <sys/module.h>
37*e18b97bdSRandall Stewart #include <sys/kernel.h>
38*e18b97bdSRandall Stewart #ifdef TCP_HHOOK
39*e18b97bdSRandall Stewart #include <sys/hhook.h>
40*e18b97bdSRandall Stewart #endif
41*e18b97bdSRandall Stewart #include <sys/lock.h>
42*e18b97bdSRandall Stewart #include <sys/malloc.h>
43*e18b97bdSRandall Stewart #include <sys/lock.h>
44*e18b97bdSRandall Stewart #include <sys/mutex.h>
45*e18b97bdSRandall Stewart #include <sys/mbuf.h>
46*e18b97bdSRandall Stewart #include <sys/proc.h> /* for proc0 declaration */
47*e18b97bdSRandall Stewart #include <sys/socket.h>
48*e18b97bdSRandall Stewart #include <sys/socketvar.h>
49*e18b97bdSRandall Stewart #include <sys/sysctl.h>
50*e18b97bdSRandall Stewart #include <sys/systm.h>
51*e18b97bdSRandall Stewart #ifdef STATS
52*e18b97bdSRandall Stewart #include <sys/qmath.h>
53*e18b97bdSRandall Stewart #include <sys/tree.h>
54*e18b97bdSRandall Stewart #include <sys/stats.h> /* Must come after qmath.h and tree.h */
55*e18b97bdSRandall Stewart #else
56*e18b97bdSRandall Stewart #include <sys/tree.h>
57*e18b97bdSRandall Stewart #endif
58*e18b97bdSRandall Stewart #include <sys/refcount.h>
59*e18b97bdSRandall Stewart #include <sys/queue.h>
60*e18b97bdSRandall Stewart #include <sys/tim_filter.h>
61*e18b97bdSRandall Stewart #include <sys/smp.h>
62*e18b97bdSRandall Stewart #include <sys/kthread.h>
63*e18b97bdSRandall Stewart #include <sys/kern_prefetch.h>
64*e18b97bdSRandall Stewart #include <sys/protosw.h>
65*e18b97bdSRandall Stewart #ifdef TCP_ACCOUNTING
66*e18b97bdSRandall Stewart #include <sys/sched.h>
67*e18b97bdSRandall Stewart #include <machine/cpu.h>
68*e18b97bdSRandall Stewart #endif
69*e18b97bdSRandall Stewart #include <vm/uma.h>
70*e18b97bdSRandall Stewart
71*e18b97bdSRandall Stewart #include <net/route.h>
72*e18b97bdSRandall Stewart #include <net/route/nhop.h>
73*e18b97bdSRandall Stewart #include <net/vnet.h>
74*e18b97bdSRandall Stewart
75*e18b97bdSRandall Stewart #define TCPSTATES /* for logging */
76*e18b97bdSRandall Stewart
77*e18b97bdSRandall Stewart #include <netinet/in.h>
78*e18b97bdSRandall Stewart #include <netinet/in_kdtrace.h>
79*e18b97bdSRandall Stewart #include <netinet/in_pcb.h>
80*e18b97bdSRandall Stewart #include <netinet/ip.h>
81*e18b97bdSRandall Stewart #include <netinet/ip_icmp.h> /* required for icmp_var.h */
82*e18b97bdSRandall Stewart #include <netinet/icmp_var.h> /* for ICMP_BANDLIM */
83*e18b97bdSRandall Stewart #include <netinet/ip_var.h>
84*e18b97bdSRandall Stewart #include <netinet/ip6.h>
85*e18b97bdSRandall Stewart #include <netinet6/in6_pcb.h>
86*e18b97bdSRandall Stewart #include <netinet6/ip6_var.h>
87*e18b97bdSRandall Stewart #include <netinet/tcp.h>
88*e18b97bdSRandall Stewart #include <netinet/tcp_fsm.h>
89*e18b97bdSRandall Stewart #include <netinet/tcp_seq.h>
90*e18b97bdSRandall Stewart #include <netinet/tcp_timer.h>
91*e18b97bdSRandall Stewart #include <netinet/tcp_var.h>
92*e18b97bdSRandall Stewart #include <netinet/tcp_log_buf.h>
93*e18b97bdSRandall Stewart #include <netinet/tcp_syncache.h>
94*e18b97bdSRandall Stewart #include <netinet/tcp_hpts.h>
95*e18b97bdSRandall Stewart #include <netinet/tcp_ratelimit.h>
96*e18b97bdSRandall Stewart #include <netinet/tcp_accounting.h>
97*e18b97bdSRandall Stewart #include <netinet/tcpip.h>
98*e18b97bdSRandall Stewart #include <netinet/cc/cc.h>
99*e18b97bdSRandall Stewart #include <netinet/cc/cc_newreno.h>
100*e18b97bdSRandall Stewart #include <netinet/tcp_fastopen.h>
101*e18b97bdSRandall Stewart #include <netinet/tcp_lro.h>
102*e18b97bdSRandall Stewart #ifdef NETFLIX_SHARED_CWND
103*e18b97bdSRandall Stewart #include <netinet/tcp_shared_cwnd.h>
104*e18b97bdSRandall Stewart #endif
105*e18b97bdSRandall Stewart #ifdef TCP_OFFLOAD
106*e18b97bdSRandall Stewart #include <netinet/tcp_offload.h>
107*e18b97bdSRandall Stewart #endif
108*e18b97bdSRandall Stewart #ifdef INET6
109*e18b97bdSRandall Stewart #include <netinet6/tcp6_var.h>
110*e18b97bdSRandall Stewart #endif
111*e18b97bdSRandall Stewart #include <netinet/tcp_ecn.h>
112*e18b97bdSRandall Stewart
113*e18b97bdSRandall Stewart #include <netipsec/ipsec_support.h>
114*e18b97bdSRandall Stewart
115*e18b97bdSRandall Stewart #if defined(IPSEC) || defined(IPSEC_SUPPORT)
116*e18b97bdSRandall Stewart #include <netipsec/ipsec.h>
117*e18b97bdSRandall Stewart #include <netipsec/ipsec6.h>
118*e18b97bdSRandall Stewart #endif /* IPSEC */
119*e18b97bdSRandall Stewart
120*e18b97bdSRandall Stewart #include <netinet/udp.h>
121*e18b97bdSRandall Stewart #include <netinet/udp_var.h>
122*e18b97bdSRandall Stewart #include <machine/in_cksum.h>
123*e18b97bdSRandall Stewart
124*e18b97bdSRandall Stewart #ifdef MAC
125*e18b97bdSRandall Stewart #include <security/mac/mac_framework.h>
126*e18b97bdSRandall Stewart #endif
127*e18b97bdSRandall Stewart #include "sack_filter.h"
128*e18b97bdSRandall Stewart #include "tcp_rack.h"
129*e18b97bdSRandall Stewart #include "tailq_hash.h"
130*e18b97bdSRandall Stewart #include "rack_bbr_common.h"
131*e18b97bdSRandall Stewart
132*e18b97bdSRandall Stewart MALLOC_DECLARE(M_TCPPCM);
133*e18b97bdSRandall Stewart
134*e18b97bdSRandall Stewart void
rack_update_pcm_ack(struct tcp_rack * rack,int was_cumack,uint32_t start,uint32_t end)135*e18b97bdSRandall Stewart rack_update_pcm_ack(struct tcp_rack *rack, int was_cumack, uint32_t start, uint32_t end)
136*e18b97bdSRandall Stewart {
137*e18b97bdSRandall Stewart struct rack_pcm_stats *e;
138*e18b97bdSRandall Stewart int i, completed = 0;
139*e18b97bdSRandall Stewart uint64_t ack_arrival;
140*e18b97bdSRandall Stewart int segsiz;
141*e18b97bdSRandall Stewart
142*e18b97bdSRandall Stewart if (rack->pcm_in_progress == 0)
143*e18b97bdSRandall Stewart return;
144*e18b97bdSRandall Stewart
145*e18b97bdSRandall Stewart if (SEQ_LEQ(end, rack->r_ctl.pcm_i.sseq)) {
146*e18b97bdSRandall Stewart /*
147*e18b97bdSRandall Stewart * Its not in our range of data sent, it
148*e18b97bdSRandall Stewart * is before our first seq.
149*e18b97bdSRandall Stewart */
150*e18b97bdSRandall Stewart return;
151*e18b97bdSRandall Stewart }
152*e18b97bdSRandall Stewart /* We take away 1 mss from the end to avoid delayed ack */
153*e18b97bdSRandall Stewart segsiz = ctf_fixed_maxseg(rack->rc_tp);
154*e18b97bdSRandall Stewart if (SEQ_GEQ(end, (rack->r_ctl.pcm_i.eseq - segsiz))) {
155*e18b97bdSRandall Stewart /*
156*e18b97bdSRandall Stewart * We have reached beyond the end of the
157*e18b97bdSRandall Stewart * initial send. Even though things may
158*e18b97bdSRandall Stewart * still be lost and this could be something
159*e18b97bdSRandall Stewart * from a different send than our burst.
160*e18b97bdSRandall Stewart */
161*e18b97bdSRandall Stewart completed = 1;
162*e18b97bdSRandall Stewart rack->pcm_in_progress = 0;
163*e18b97bdSRandall Stewart rack->r_ctl.last_pcm_round = rack->r_ctl.current_round;
164*e18b97bdSRandall Stewart rack->r_ctl.pcm_idle_rounds = 0;
165*e18b97bdSRandall Stewart }
166*e18b97bdSRandall Stewart if (SEQ_GEQ(start, rack->r_ctl.pcm_i.eseq)) {
167*e18b97bdSRandall Stewart /*
168*e18b97bdSRandall Stewart * This is outside the scope
169*e18b97bdSRandall Stewart * of the measurement itself and
170*e18b97bdSRandall Stewart * is likely a sack above our burst.
171*e18b97bdSRandall Stewart */
172*e18b97bdSRandall Stewart goto skip_ack_accounting;
173*e18b97bdSRandall Stewart }
174*e18b97bdSRandall Stewart /*
175*e18b97bdSRandall Stewart * Record ACK data.
176*e18b97bdSRandall Stewart */
177*e18b97bdSRandall Stewart ack_arrival = tcp_tv_to_lusectick(&rack->r_ctl.act_rcv_time);
178*e18b97bdSRandall Stewart if (SEQ_GT(end, rack->r_ctl.pcm_i.eseq)) {
179*e18b97bdSRandall Stewart /* Trim the end to the end of our range if it is beyond */
180*e18b97bdSRandall Stewart end = rack->r_ctl.pcm_i.eseq;
181*e18b97bdSRandall Stewart }
182*e18b97bdSRandall Stewart if ((rack->r_ctl.pcm_i.cnt + 1) > rack->r_ctl.pcm_i.cnt_alloc) {
183*e18b97bdSRandall Stewart /* Need to expand, first is there any present? */
184*e18b97bdSRandall Stewart size_t sz;
185*e18b97bdSRandall Stewart
186*e18b97bdSRandall Stewart if (rack->r_ctl.pcm_i.cnt_alloc == 0) {
187*e18b97bdSRandall Stewart /*
188*e18b97bdSRandall Stewart * Failed at rack_init I suppose.
189*e18b97bdSRandall Stewart */
190*e18b97bdSRandall Stewart rack->r_ctl.pcm_i.cnt_alloc = RACK_DEFAULT_PCM_ARRAY;
191*e18b97bdSRandall Stewart sz = (sizeof(struct rack_pcm_stats) * rack->r_ctl.pcm_i.cnt_alloc);
192*e18b97bdSRandall Stewart rack->r_ctl.pcm_s = malloc(sz, M_TCPPCM, M_NOWAIT);
193*e18b97bdSRandall Stewart if (rack->r_ctl.pcm_s == NULL) {
194*e18b97bdSRandall Stewart rack->r_ctl.pcm_i.cnt_alloc = 0;
195*e18b97bdSRandall Stewart rack->pcm_in_progress = 0;
196*e18b97bdSRandall Stewart return;
197*e18b97bdSRandall Stewart }
198*e18b97bdSRandall Stewart } else {
199*e18b97bdSRandall Stewart /* Need to expand the array */
200*e18b97bdSRandall Stewart struct rack_pcm_stats *n;
201*e18b97bdSRandall Stewart uint16_t new_cnt;
202*e18b97bdSRandall Stewart
203*e18b97bdSRandall Stewart new_cnt = rack->r_ctl.pcm_i.cnt_alloc * 2;
204*e18b97bdSRandall Stewart sz = (sizeof(struct rack_pcm_stats) * new_cnt);
205*e18b97bdSRandall Stewart n = malloc(sz,M_TCPPCM, M_NOWAIT);
206*e18b97bdSRandall Stewart if (n == NULL) {
207*e18b97bdSRandall Stewart /* We are dead, no memory */
208*e18b97bdSRandall Stewart rack->pcm_in_progress = 0;
209*e18b97bdSRandall Stewart rack->r_ctl.pcm_i.cnt = 0;
210*e18b97bdSRandall Stewart return;
211*e18b97bdSRandall Stewart }
212*e18b97bdSRandall Stewart sz = (sizeof(struct rack_pcm_stats) * rack->r_ctl.pcm_i.cnt_alloc);
213*e18b97bdSRandall Stewart memcpy(n, rack->r_ctl.pcm_s, sz);
214*e18b97bdSRandall Stewart free(rack->r_ctl.pcm_s, M_TCPPCM);
215*e18b97bdSRandall Stewart rack->r_ctl.pcm_s = n;
216*e18b97bdSRandall Stewart rack->r_ctl.pcm_i.cnt_alloc = new_cnt;
217*e18b97bdSRandall Stewart }
218*e18b97bdSRandall Stewart }
219*e18b97bdSRandall Stewart e = &rack->r_ctl.pcm_s[rack->r_ctl.pcm_i.cnt];
220*e18b97bdSRandall Stewart rack->r_ctl.pcm_i.cnt++;
221*e18b97bdSRandall Stewart e->sseq = start;
222*e18b97bdSRandall Stewart e->eseq = end;
223*e18b97bdSRandall Stewart e->ack_time = ack_arrival;
224*e18b97bdSRandall Stewart skip_ack_accounting:
225*e18b97bdSRandall Stewart if (completed == 0)
226*e18b97bdSRandall Stewart return;
227*e18b97bdSRandall Stewart /*
228*e18b97bdSRandall Stewart * Ok we are to the point where we can assess what
229*e18b97bdSRandall Stewart * has happened and make a PCM judgement.
230*e18b97bdSRandall Stewart */
231*e18b97bdSRandall Stewart
232*e18b97bdSRandall Stewart if (tcp_bblogging_on(rack->rc_tp)) {
233*e18b97bdSRandall Stewart union tcp_log_stackspecific log;
234*e18b97bdSRandall Stewart struct timeval tv;
235*e18b97bdSRandall Stewart uint64_t prev_time = 0;
236*e18b97bdSRandall Stewart uint64_t tot_byt = 0;
237*e18b97bdSRandall Stewart uint32_t tot_lt_12us = 0;
238*e18b97bdSRandall Stewart uint32_t tot_gt_2mss = 0;
239*e18b97bdSRandall Stewart
240*e18b97bdSRandall Stewart (void)tcp_get_usecs(&tv);
241*e18b97bdSRandall Stewart for (i=0; i<rack->r_ctl.pcm_i.cnt; i++) {
242*e18b97bdSRandall Stewart
243*e18b97bdSRandall Stewart e = &rack->r_ctl.pcm_s[i];
244*e18b97bdSRandall Stewart memset(&log.u_bbr, 0, sizeof(log.u_bbr));
245*e18b97bdSRandall Stewart log.u_bbr.timeStamp = tcp_tv_to_usectick(&tv);
246*e18b97bdSRandall Stewart log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
247*e18b97bdSRandall Stewart log.u_bbr.flex8 = 1;
248*e18b97bdSRandall Stewart log.u_bbr.flex1 = e->sseq;
249*e18b97bdSRandall Stewart log.u_bbr.flex2 = e->eseq;
250*e18b97bdSRandall Stewart tot_byt += (e->eseq - e->sseq);
251*e18b97bdSRandall Stewart if ((i > 0) &&
252*e18b97bdSRandall Stewart (e->ack_time > prev_time)) {
253*e18b97bdSRandall Stewart log.u_bbr.flex3 = (uint32_t)(e->ack_time - prev_time);
254*e18b97bdSRandall Stewart } else {
255*e18b97bdSRandall Stewart log.u_bbr.flex3 = 0;
256*e18b97bdSRandall Stewart }
257*e18b97bdSRandall Stewart if (e->ack_time > rack->r_ctl.pcm_i.send_time) {
258*e18b97bdSRandall Stewart log.u_bbr.flex4 = (uint32_t)(e->ack_time - rack->r_ctl.pcm_i.send_time);
259*e18b97bdSRandall Stewart } else {
260*e18b97bdSRandall Stewart log.u_bbr.flex4 = 0;
261*e18b97bdSRandall Stewart }
262*e18b97bdSRandall Stewart if ((e->eseq - e->sseq) > (segsiz * 2)) {
263*e18b97bdSRandall Stewart tot_gt_2mss++;
264*e18b97bdSRandall Stewart }
265*e18b97bdSRandall Stewart if ((i > 0) &&
266*e18b97bdSRandall Stewart (log.u_bbr.flex3 < 12)) {
267*e18b97bdSRandall Stewart tot_lt_12us++;
268*e18b97bdSRandall Stewart }
269*e18b97bdSRandall Stewart prev_time = e->ack_time;
270*e18b97bdSRandall Stewart log.u_bbr.cur_del_rate = rack->r_ctl.pcm_i.send_time;
271*e18b97bdSRandall Stewart if ((i > 0) &&
272*e18b97bdSRandall Stewart (log.u_bbr.flex3 > 0)) {
273*e18b97bdSRandall Stewart /*
274*e18b97bdSRandall Stewart * Calculate a b/w between this chunk and the previous.
275*e18b97bdSRandall Stewart */
276*e18b97bdSRandall Stewart log.u_bbr.delRate = (e->eseq - e->sseq);
277*e18b97bdSRandall Stewart log.u_bbr.delRate *= HPTS_USEC_IN_SEC;
278*e18b97bdSRandall Stewart log.u_bbr.delRate /= (uint64_t)log.u_bbr.flex3;
279*e18b97bdSRandall Stewart }
280*e18b97bdSRandall Stewart log.u_bbr.rttProp = e->ack_time;
281*e18b97bdSRandall Stewart (void)tcp_log_event(rack->rc_tp, NULL, NULL, NULL, TCP_PCM_MEASURE, ERRNO_UNK,
282*e18b97bdSRandall Stewart 0, &log, false, NULL, NULL, 0, &tv);
283*e18b97bdSRandall Stewart }
284*e18b97bdSRandall Stewart if (prev_time > rack->r_ctl.pcm_i.send_time) {
285*e18b97bdSRandall Stewart /*
286*e18b97bdSRandall Stewart * Prev time holds the last ack arrival time.
287*e18b97bdSRandall Stewart */
288*e18b97bdSRandall Stewart memset(&log.u_bbr, 0, sizeof(log.u_bbr));
289*e18b97bdSRandall Stewart log.u_bbr.timeStamp = tcp_tv_to_usectick(&tv);
290*e18b97bdSRandall Stewart log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
291*e18b97bdSRandall Stewart log.u_bbr.flex8 = 2;
292*e18b97bdSRandall Stewart log.u_bbr.flex1 = rack->r_ctl.pcm_i.sseq;
293*e18b97bdSRandall Stewart log.u_bbr.flex2 = rack->r_ctl.pcm_i.eseq;
294*e18b97bdSRandall Stewart log.u_bbr.flex3 = tot_byt;
295*e18b97bdSRandall Stewart log.u_bbr.flex4 = tot_lt_12us; /* How many deltas indicate > 2Gbps */
296*e18b97bdSRandall Stewart log.u_bbr.flex5 = tot_gt_2mss; /* How many acks represent more than 2MSS */
297*e18b97bdSRandall Stewart log.u_bbr.flex7 = rack->r_ctl.pcm_i.cnt;
298*e18b97bdSRandall Stewart log.u_bbr.cwnd_gain = rack->r_ctl.pcm_i.cnt_alloc;
299*e18b97bdSRandall Stewart log.u_bbr.cur_del_rate = rack->r_ctl.pcm_i.send_time;
300*e18b97bdSRandall Stewart log.u_bbr.rttProp = prev_time;
301*e18b97bdSRandall Stewart log.u_bbr.delRate = tot_byt;
302*e18b97bdSRandall Stewart log.u_bbr.delRate *= HPTS_USEC_IN_SEC;
303*e18b97bdSRandall Stewart log.u_bbr.delRate /= (prev_time - rack->r_ctl.pcm_i.send_time);
304*e18b97bdSRandall Stewart (void)tcp_log_event(rack->rc_tp, NULL, NULL, NULL, TCP_PCM_MEASURE, ERRNO_UNK,
305*e18b97bdSRandall Stewart 0, &log, false, NULL, NULL, 0, &tv);
306*e18b97bdSRandall Stewart }
307*e18b97bdSRandall Stewart }
308*e18b97bdSRandall Stewart /*
309*e18b97bdSRandall Stewart * Here we need a lot to be added including:
310*e18b97bdSRandall Stewart * 1) Some form of measurement, where if we think the measurement
311*e18b97bdSRandall Stewart * is valid we iterate over the PCM data and come up with a path
312*e18b97bdSRandall Stewart * capacity estimate.
313*e18b97bdSRandall Stewart * 2) We may decide that the PCM is invalid due to ack meddlers and
314*e18b97bdSRandall Stewart * thus need to increase the PCM size (which defaults to 10mss).
315*e18b97bdSRandall Stewart * 3) We may need to think about shrinking the PCM size if we are
316*e18b97bdSRandall Stewart * seeing some sort of presistent loss from making the measurement
317*e18b97bdSRandall Stewart * (i.e. it got to big and our bursts are causing loss).
318*e18b97bdSRandall Stewart * 4) If we make a measurement we need to place it somewhere in the
319*e18b97bdSRandall Stewart * stack to be reported later somehow. Is it a WMA in the stack or
320*e18b97bdSRandall Stewart * the highest or?
321*e18b97bdSRandall Stewart * 5) Is there a limit on how big we can go PCM size wise, the code
322*e18b97bdSRandall Stewart * here will send multiple TSO bursts all at once, but how big
323*e18b97bdSRandall Stewart * is too big, and does that then put some bound (I think it does)
324*e18b97bdSRandall Stewart * on the largest capacity we can determine?
325*e18b97bdSRandall Stewart */
326*e18b97bdSRandall Stewart /* New code here */
327*e18b97bdSRandall Stewart /* Clear the cnt we are done */
328*e18b97bdSRandall Stewart rack->r_ctl.pcm_i.cnt = 0;
329*e18b97bdSRandall Stewart }
330*e18b97bdSRandall Stewart
331*e18b97bdSRandall Stewart #endif /* #if !defined(INET) && !defined(INET6) */
332