]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/tcp_hpts.h
login(1): when exporting variables check the result of setenv(3)
[FreeBSD/FreeBSD.git] / sys / netinet / tcp_hpts.h
1 /*-
2  * Copyright (c) 2016-2018 Netflix, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27
28 #ifndef __tcp_hpts_h__
29 #define __tcp_hpts_h__
30
31 /*
32  * The hpts uses a 102400 wheel. The wheel
33  * defines the time in 10 usec increments (102400 x 10).
34  * This gives a range of 10usec - 1024ms to place
35  * an entry within. If the user requests more than
36  * 1.024 second, a remaineder is attached and the hpts
37  * when seeing the remainder will re-insert the
38  * inpcb forward in time from where it is until
39  * the remainder is zero.
40  */
41
42 #define NUM_OF_HPTSI_SLOTS 102400
43
44 TAILQ_HEAD(hptsh, inpcb);
45
46 /* Number of useconds in a hpts tick */
47 #define HPTS_TICKS_PER_USEC 10
48 #define HPTS_MS_TO_SLOTS(x) ((x * 100) + 1)
49 #define HPTS_USEC_TO_SLOTS(x) ((x+9) /10)
50 #define HPTS_USEC_IN_SEC 1000000
51 #define HPTS_MSEC_IN_SEC 1000
52 #define HPTS_USEC_IN_MSEC 1000
53
54 struct hpts_diag {
55         uint32_t p_hpts_active;         /* bbr->flex7 x */
56         uint32_t p_nxt_slot;            /* bbr->flex1 x */
57         uint32_t p_cur_slot;            /* bbr->flex2 x */
58         uint32_t p_prev_slot;           /* bbr->delivered */
59         uint32_t p_runningtick;         /* bbr->inflight */
60         uint32_t slot_req;              /* bbr->flex3 x */
61         uint32_t inp_hptsslot;          /* bbr->flex4 x */
62         uint32_t slot_remaining;        /* bbr->flex5 x */
63         uint32_t have_slept;            /* bbr->epoch x */
64         uint32_t hpts_sleep_time;       /* bbr->applimited x */
65         uint32_t yet_to_sleep;          /* bbr->lt_epoch x */
66         uint32_t need_new_to;           /* bbr->flex6 x  */
67         uint32_t wheel_tick;            /* bbr->bw_inuse x */
68         uint32_t maxticks;              /* bbr->delRate x */
69         uint32_t wheel_cts;             /* bbr->rttProp x */
70         int32_t co_ret;                 /* bbr->pkts_out x */
71         uint32_t p_curtick;             /* upper bbr->cur_del_rate */
72         uint32_t p_lasttick;            /* lower bbr->cur_del_rate */
73         uint8_t p_on_min_sleep;         /* bbr->flex8 x */
74 };
75
76 /* Magic flags to tell whats cooking on the pacing wheel */
77 #define PACE_TMR_DELACK 0x01    /* Delayed ack timer running */
78 #define PACE_TMR_RACK   0x02    /* RACK timer running */
79 #define PACE_TMR_TLP    0x04    /* TLP timer running */
80 #define PACE_TMR_RXT    0x08    /* Retransmit timer running */
81 #define PACE_TMR_PERSIT 0x10    /* Persists timer running */
82 #define PACE_TMR_KEEP   0x20    /* Keep alive timer running */
83 #define PACE_PKT_OUTPUT 0x40    /* Output Packets being paced */
84 #define PACE_TMR_MASK   (PACE_TMR_KEEP|PACE_TMR_PERSIT|PACE_TMR_RXT|PACE_TMR_TLP|PACE_TMR_RACK|PACE_TMR_DELACK)
85
86 #ifdef _KERNEL
87 /* Each hpts has its own p_mtx which is used for locking */
88 struct tcp_hpts_entry {
89         /* Cache line 0x00 */
90         struct mtx p_mtx;       /* Mutex for hpts */
91         uint16_t p_hpts_active; /* Flag that says hpts is awake  */
92         uint8_t p_hpts_wake_scheduled;  /* Have we scheduled a wakeup? */
93         uint8_t p_wheel_complete; /* have we completed the wheel arc walk? */
94         uint32_t p_curtick;     /* Tick in 10 us the hpts is going to */
95         uint32_t p_runningtick; /* Current tick we are at if we are running */
96         uint32_t p_prev_slot;   /* Previous slot we were on */
97         uint32_t p_cur_slot;    /* Current slot in wheel hpts is draining */
98         uint32_t p_nxt_slot;    /* The next slot outside the current range of
99                                  * slots that the hpts is running on. */
100         int32_t p_on_queue_cnt; /* Count on queue in this hpts */
101         uint32_t p_lasttick;    /* Last tick before the current one */
102         uint8_t p_direct_wake :1, /* boolean */
103                 p_on_min_sleep:1, /* boolean */
104                 p_avail:6;
105         uint8_t p_fill[3];        /* Fill to 32 bits */
106         /* Cache line 0x40 */
107         void *p_inp;
108         struct hptsh p_input;   /* For the tcp-input runner */
109         /* Hptsi wheel */
110         struct hptsh *p_hptss;
111         int32_t p_on_inqueue_cnt; /* Count on input queue in this hpts */
112         uint32_t hit_no_enobuf;
113         uint32_t p_dyn_adjust;
114         uint32_t p_hpts_sleep_time;     /* Current sleep interval having a max
115                                          * of 255ms */
116         uint32_t overidden_sleep;       /* what was overrided by min-sleep for logging */
117         uint32_t saved_lasttick;        /* for logging */
118         uint32_t saved_curtick;         /* for logging */
119         uint32_t saved_curslot;         /* for logging */
120         uint32_t saved_prev_slot;       /* for logging */
121         uint32_t p_delayed_by;  /* How much were we delayed by */
122         /* Cache line 0x80 */
123         struct sysctl_ctx_list hpts_ctx;
124         struct sysctl_oid *hpts_root;
125         struct intr_event *ie;
126         void *ie_cookie;
127         uint16_t p_num;         /* The hpts number one per cpu */
128         uint16_t p_cpu;         /* The hpts CPU */
129         /* There is extra space in here */
130         /* Cache line 0x100 */
131         struct callout co __aligned(CACHE_LINE_SIZE);
132 }               __aligned(CACHE_LINE_SIZE);
133
134 struct tcp_hptsi {
135         struct proc *rp_proc;   /* Process structure for hpts */
136         struct tcp_hpts_entry **rp_ent; /* Array of hptss */
137         uint32_t rp_num_hptss;  /* Number of hpts threads */
138 };
139
140 #endif
141
142 #define HPTS_REMOVE_INPUT  0x01
143 #define HPTS_REMOVE_OUTPUT 0x02
144 #define HPTS_REMOVE_ALL    (HPTS_REMOVE_INPUT | HPTS_REMOVE_OUTPUT)
145
146 /*
147  * When using the hpts, a TCP stack must make sure
148  * that once a INP_DROPPED flag is applied to a INP
149  * that it does not expect tcp_output() to ever be
150  * called by the hpts. The hpts will *not* call
151  * any output (or input) functions on a TCB that
152  * is in the DROPPED state.
153  *
154  * This implies final ACK's and RST's that might
155  * be sent when a TCB is still around must be
156  * sent from a routine like tcp_respond().
157  */
158 #define DEFAULT_MIN_SLEEP 250   /* How many usec's is default for hpts sleep
159                                  * this determines min granularity of the
160                                  * hpts. If 0, granularity is 10useconds at
161                                  * the cost of more CPU (context switching). */
162 #ifdef _KERNEL
163 #define HPTS_MTX_ASSERT(hpts) mtx_assert(&(hpts)->p_mtx, MA_OWNED)
164 struct tcp_hpts_entry *tcp_hpts_lock(struct inpcb *inp);
165 struct tcp_hpts_entry *tcp_input_lock(struct inpcb *inp);
166 int __tcp_queue_to_hpts_immediate(struct inpcb *inp, int32_t line);
167 #define tcp_queue_to_hpts_immediate(a)__tcp_queue_to_hpts_immediate(a, __LINE__)
168
169 struct tcp_hpts_entry *tcp_cur_hpts(struct inpcb *inp);
170 #define tcp_hpts_remove(a, b) __tcp_hpts_remove(a, b, __LINE__)
171 void __tcp_hpts_remove(struct inpcb *inp, int32_t flags, int32_t line);
172
173 /*
174  * To insert a TCB on the hpts you *must* be holding the
175  * INP_WLOCK(). The hpts insert code will then acqurire
176  * the hpts's lock and insert the TCB on the requested
177  * slot possibly waking up the hpts if you are requesting
178  * a time earlier than what the hpts is sleeping to (if
179  * the hpts is sleeping). You may check the inp->inp_in_hpts
180  * flag without the hpts lock. The hpts is the only one
181  * that will clear this flag holding only the hpts lock. This
182  * means that in your tcp_output() routine when you test for
183  * it to be 1 (so you wont call output) it may be transitioning
184  * to 0 (by the hpts). That will be fine since that will just
185  * mean an extra call to tcp_output that most likely will find
186  * the call you executed (when the mis-match occured) will have
187  * put the TCB back on the hpts and it will return. If your
188  * call did not add it back to the hpts then you will either
189  * over-send or the cwnd will block you from sending more.
190  *
191  * Note you should also be holding the INP_WLOCK() when you
192  * call the remove from the hpts as well. Thoug usually
193  * you are either doing this from a timer, where you need
194  * that INP_WLOCK() or from destroying your TCB where again
195  * you should already have the INP_WLOCK().
196  */
197 uint32_t __tcp_hpts_insert(struct inpcb *inp, uint32_t slot, int32_t line);
198 #define tcp_hpts_insert(a, b) __tcp_hpts_insert(a, b, __LINE__)
199
200 uint32_t
201 tcp_hpts_insert_diag(struct inpcb *inp, uint32_t slot, int32_t line, struct hpts_diag *diag);
202
203 int
204     __tcp_queue_to_input_locked(struct inpcb *inp, struct tcp_hpts_entry *hpts, int32_t line);
205 #define tcp_queue_to_input_locked(a, b) __tcp_queue_to_input_locked(a, b, __LINE__);
206 int
207 __tcp_queue_to_input(struct inpcb *inp, int32_t line);
208 #define tcp_queue_to_input(a) __tcp_queue_to_input(a, __LINE__)
209
210 uint16_t tcp_hpts_delayedby(struct inpcb *inp);
211
212 void __tcp_set_hpts(struct inpcb *inp, int32_t line);
213 #define tcp_set_hpts(a) __tcp_set_hpts(a, __LINE__)
214
215 void __tcp_set_inp_to_drop(struct inpcb *inp, uint16_t reason, int32_t line);
216 #define tcp_set_inp_to_drop(a, b) __tcp_set_inp_to_drop(a, b, __LINE__)
217
218 extern int32_t tcp_min_hptsi_time;
219
220 static __inline uint32_t
221 tcp_tv_to_hptstick(struct timeval *sv)
222 {
223         return ((sv->tv_sec * 100000) + (sv->tv_usec / 10));
224 }
225
226 static __inline uint32_t
227 tcp_gethptstick(struct timeval *sv)
228 {
229         struct timeval tv;
230
231         if (sv == NULL)
232                 sv = &tv;
233         microuptime(sv);
234         return (tcp_tv_to_hptstick(sv));
235 }
236
237 static __inline uint32_t
238 tcp_tv_to_usectick(struct timeval *sv)
239 {
240         return ((uint32_t) ((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec));
241 }
242
243 static __inline uint32_t
244 tcp_tv_to_mssectick(struct timeval *sv)
245 {
246         return ((uint32_t) ((sv->tv_sec * HPTS_MSEC_IN_SEC) + (sv->tv_usec/HPTS_USEC_IN_MSEC)));
247 }
248
249 static __inline void
250 tcp_hpts_unlock(struct tcp_hpts_entry *hpts)
251 {
252         mtx_unlock(&hpts->p_mtx);
253 }
254
255 static __inline uint32_t
256 tcp_get_usecs(struct timeval *tv)
257 {
258         struct timeval tvd;
259
260         if (tv == NULL)
261                 tv = &tvd;
262         microuptime(tv);
263         return (tcp_tv_to_usectick(tv));
264 }
265
266 #endif /* _KERNEL */
267 #endif /* __tcp_hpts_h__ */