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_SLOT 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_runningslot; /* 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_slot; /* bbr->bw_inuse x */ 68 uint32_t maxslots; /* 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 #define DEFAULT_CONNECTION_THESHOLD 100 87 88 #ifdef _KERNEL 89 /* Each hpts has its own p_mtx which is used for locking */ 90 struct tcp_hpts_entry { 91 /* Cache line 0x00 */ 92 struct mtx p_mtx; /* Mutex for hpts */ 93 struct timeval p_mysleep; /* Our min sleep time */ 94 uint64_t syscall_cnt; 95 uint64_t sleeping; /* What the actual sleep was (if sleeping) */ 96 uint16_t p_hpts_active; /* Flag that says hpts is awake */ 97 uint8_t p_wheel_complete; /* have we completed the wheel arc walk? */ 98 uint32_t p_curtick; /* Tick in 10 us the hpts is going to */ 99 uint32_t p_runningslot; /* Current tick we are at if we are running */ 100 uint32_t p_prev_slot; /* Previous slot we were on */ 101 uint32_t p_cur_slot; /* Current slot in wheel hpts is draining */ 102 uint32_t p_nxt_slot; /* The next slot outside the current range of 103 * slots that the hpts is running on. */ 104 int32_t p_on_queue_cnt; /* Count on queue in this hpts */ 105 uint32_t p_lasttick; /* Last tick before the current one */ 106 uint8_t p_direct_wake :1, /* boolean */ 107 p_on_min_sleep:1, /* boolean */ 108 p_hpts_wake_scheduled:1, /* boolean */ 109 p_avail:5; 110 uint8_t p_fill[3]; /* Fill to 32 bits */ 111 /* Cache line 0x40 */ 112 void *p_inp; 113 struct hptsh p_input; /* For the tcp-input runner */ 114 /* Hptsi wheel */ 115 struct hptsh *p_hptss; 116 int32_t p_on_inqueue_cnt; /* Count on input queue in this hpts */ 117 uint32_t p_hpts_sleep_time; /* Current sleep interval having a max 118 * of 255ms */ 119 uint32_t overidden_sleep; /* what was overrided by min-sleep for logging */ 120 uint32_t saved_lasttick; /* for logging */ 121 uint32_t saved_curtick; /* for logging */ 122 uint32_t saved_curslot; /* for logging */ 123 uint32_t saved_prev_slot; /* for logging */ 124 uint32_t p_delayed_by; /* How much were we delayed by */ 125 /* Cache line 0x80 */ 126 struct sysctl_ctx_list hpts_ctx; 127 struct sysctl_oid *hpts_root; 128 struct intr_event *ie; 129 void *ie_cookie; 130 uint16_t p_num; /* The hpts number one per cpu */ 131 uint16_t p_cpu; /* The hpts CPU */ 132 /* There is extra space in here */ 133 /* Cache line 0x100 */ 134 struct callout co __aligned(CACHE_LINE_SIZE); 135 } __aligned(CACHE_LINE_SIZE); 136 137 struct tcp_hptsi { 138 struct proc *rp_proc; /* Process structure for hpts */ 139 struct tcp_hpts_entry **rp_ent; /* Array of hptss */ 140 uint32_t *cts_last_ran; 141 uint32_t rp_num_hptss; /* Number of hpts threads */ 142 }; 143 144 #endif 145 146 #define HPTS_REMOVE_INPUT 0x01 147 #define HPTS_REMOVE_OUTPUT 0x02 148 #define HPTS_REMOVE_ALL (HPTS_REMOVE_INPUT | HPTS_REMOVE_OUTPUT) 149 150 /* 151 * When using the hpts, a TCP stack must make sure 152 * that once a INP_DROPPED flag is applied to a INP 153 * that it does not expect tcp_output() to ever be 154 * called by the hpts. The hpts will *not* call 155 * any output (or input) functions on a TCB that 156 * is in the DROPPED state. 157 * 158 * This implies final ACK's and RST's that might 159 * be sent when a TCB is still around must be 160 * sent from a routine like tcp_respond(). 161 */ 162 #define LOWEST_SLEEP_ALLOWED 50 163 #define DEFAULT_MIN_SLEEP 250 /* How many usec's is default for hpts sleep 164 * this determines min granularity of the 165 * hpts. If 1, granularity is 10useconds at 166 * the cost of more CPU (context switching). 167 * Note do not set this to 0. 168 */ 169 #define DYNAMIC_MIN_SLEEP DEFAULT_MIN_SLEEP 170 #define DYNAMIC_MAX_SLEEP 100000 /* 100ms */ 171 /* No of connections when wee start aligning to the cpu from syscalls */ 172 #define OLDEST_THRESHOLD 1200 173 /* Thresholds for raising/lowering sleep */ 174 #define TICKS_INDICATE_MORE_SLEEP 100 /* This would be 1ms */ 175 #define TICKS_INDICATE_LESS_SLEEP 1000 /* This would indicate 10ms */ 176 /** 177 * 178 * Dynamic adjustment of sleeping times is done in "new" mode 179 * where we are depending on syscall returns and lro returns 180 * to push hpts forward mainly and the timer is only a backstop. 181 * 182 * When we are in the "new" mode i.e. conn_cnt > conn_cnt_thresh 183 * then we do a dynamic adjustment on the time we sleep. 184 * Our threshold is if the lateness of the first client served (in ticks) is 185 * greater than or equal too ticks_indicate_more_sleep (10ms 186 * or 10000 ticks). If we were that late, the actual sleep time 187 * is adjusted down by 50%. If the ticks_ran is less than 188 * ticks_indicate_more_sleep (100 ticks or 1000usecs). 189 * 190 */ 191 192 193 #ifdef _KERNEL 194 #define HPTS_MTX_ASSERT(hpts) mtx_assert(&(hpts)->p_mtx, MA_OWNED) 195 struct tcp_hpts_entry *tcp_hpts_lock(struct inpcb *inp); 196 struct tcp_hpts_entry *tcp_input_lock(struct inpcb *inp); 197 int __tcp_queue_to_hpts_immediate(struct inpcb *inp, int32_t line); 198 #define tcp_queue_to_hpts_immediate(a)__tcp_queue_to_hpts_immediate(a, __LINE__) 199 200 struct tcp_hpts_entry *tcp_cur_hpts(struct inpcb *inp); 201 #define tcp_hpts_remove(a, b) __tcp_hpts_remove(a, b, __LINE__) 202 void __tcp_hpts_remove(struct inpcb *inp, int32_t flags, int32_t line); 203 204 /* 205 * To insert a TCB on the hpts you *must* be holding the 206 * INP_WLOCK(). The hpts insert code will then acqurire 207 * the hpts's lock and insert the TCB on the requested 208 * slot possibly waking up the hpts if you are requesting 209 * a time earlier than what the hpts is sleeping to (if 210 * the hpts is sleeping). You may check the inp->inp_in_hpts 211 * flag without the hpts lock. The hpts is the only one 212 * that will clear this flag holding only the hpts lock. This 213 * means that in your tcp_output() routine when you test for 214 * it to be 1 (so you wont call output) it may be transitioning 215 * to 0 (by the hpts). That will be fine since that will just 216 * mean an extra call to tcp_output that most likely will find 217 * the call you executed (when the mis-match occured) will have 218 * put the TCB back on the hpts and it will return. If your 219 * call did not add it back to the hpts then you will either 220 * over-send or the cwnd will block you from sending more. 221 * 222 * Note you should also be holding the INP_WLOCK() when you 223 * call the remove from the hpts as well. Thoug usually 224 * you are either doing this from a timer, where you need 225 * that INP_WLOCK() or from destroying your TCB where again 226 * you should already have the INP_WLOCK(). 227 */ 228 uint32_t __tcp_hpts_insert(struct inpcb *inp, uint32_t slot, int32_t line); 229 #define tcp_hpts_insert(a, b) __tcp_hpts_insert(a, b, __LINE__) 230 231 uint32_t 232 tcp_hpts_insert_diag(struct inpcb *inp, uint32_t slot, int32_t line, struct hpts_diag *diag); 233 234 int 235 __tcp_queue_to_input_locked(struct inpcb *inp, struct tcp_hpts_entry *hpts, int32_t line); 236 #define tcp_queue_to_input_locked(a, b) __tcp_queue_to_input_locked(a, b, __LINE__); 237 int 238 __tcp_queue_to_input(struct inpcb *inp, int32_t line); 239 #define tcp_queue_to_input(a) __tcp_queue_to_input(a, __LINE__) 240 241 uint16_t tcp_hpts_delayedby(struct inpcb *inp); 242 243 void __tcp_set_hpts(struct inpcb *inp, int32_t line); 244 #define tcp_set_hpts(a) __tcp_set_hpts(a, __LINE__) 245 246 void __tcp_set_inp_to_drop(struct inpcb *inp, uint16_t reason, int32_t line); 247 #define tcp_set_inp_to_drop(a, b) __tcp_set_inp_to_drop(a, b, __LINE__) 248 249 void tcp_run_hpts(void); 250 251 uint16_t hpts_random_cpu(struct inpcb *inp); 252 253 extern int32_t tcp_min_hptsi_time; 254 255 #endif /* _KERNEL */ 256 257 /* 258 * The following functions should also be available 259 * to userspace as well. 260 */ 261 static __inline uint32_t 262 tcp_tv_to_hptstick(const struct timeval *sv) 263 { 264 return ((sv->tv_sec * 100000) + (sv->tv_usec / HPTS_TICKS_PER_SLOT)); 265 } 266 267 static __inline uint32_t 268 tcp_tv_to_usectick(const struct timeval *sv) 269 { 270 return ((uint32_t) ((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec)); 271 } 272 273 static __inline uint32_t 274 tcp_tv_to_mssectick(const struct timeval *sv) 275 { 276 return ((uint32_t) ((sv->tv_sec * HPTS_MSEC_IN_SEC) + (sv->tv_usec/HPTS_USEC_IN_MSEC))); 277 } 278 279 static __inline uint64_t 280 tcp_tv_to_lusectick(const struct timeval *sv) 281 { 282 return ((uint64_t)((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec)); 283 } 284 285 #ifdef _KERNEL 286 287 static __inline void 288 tcp_hpts_unlock(struct tcp_hpts_entry *hpts) 289 { 290 mtx_unlock(&hpts->p_mtx); 291 } 292 293 static __inline uint32_t 294 tcp_gethptstick(struct timeval *sv) 295 { 296 struct timeval tv; 297 298 if (sv == NULL) 299 sv = &tv; 300 microuptime(sv); 301 return (tcp_tv_to_hptstick(sv)); 302 } 303 304 static __inline uint32_t 305 tcp_get_usecs(struct timeval *tv) 306 { 307 struct timeval tvd; 308 309 if (tv == NULL) 310 tv = &tvd; 311 microuptime(tv); 312 return (tcp_tv_to_usectick(tv)); 313 } 314 315 #endif /* _KERNEL */ 316 #endif /* __tcp_hpts_h__ */ 317