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 /* Number of useconds in a hpts tick */ 32 #define HPTS_TICKS_PER_SLOT 10 33 #define HPTS_MS_TO_SLOTS(x) ((x * 100) + 1) 34 #define HPTS_USEC_TO_SLOTS(x) ((x+9) /10) 35 #define HPTS_USEC_IN_SEC 1000000 36 #define HPTS_MSEC_IN_SEC 1000 37 #define HPTS_USEC_IN_MSEC 1000 38 39 struct hpts_diag { 40 uint32_t p_hpts_active; /* bbr->flex7 x */ 41 uint32_t p_nxt_slot; /* bbr->flex1 x */ 42 uint32_t p_cur_slot; /* bbr->flex2 x */ 43 uint32_t p_prev_slot; /* bbr->delivered */ 44 uint32_t p_runningslot; /* bbr->inflight */ 45 uint32_t slot_req; /* bbr->flex3 x */ 46 uint32_t inp_hptsslot; /* bbr->flex4 x */ 47 uint32_t slot_remaining; /* bbr->flex5 x */ 48 uint32_t have_slept; /* bbr->epoch x */ 49 uint32_t hpts_sleep_time; /* bbr->applimited x */ 50 uint32_t yet_to_sleep; /* bbr->lt_epoch x */ 51 uint32_t need_new_to; /* bbr->flex6 x */ 52 uint32_t wheel_slot; /* bbr->bw_inuse x */ 53 uint32_t maxslots; /* bbr->delRate x */ 54 uint32_t wheel_cts; /* bbr->rttProp x */ 55 int32_t co_ret; /* bbr->pkts_out x */ 56 uint32_t p_curtick; /* upper bbr->cur_del_rate */ 57 uint32_t p_lasttick; /* lower bbr->cur_del_rate */ 58 uint8_t p_on_min_sleep; /* bbr->flex8 x */ 59 }; 60 61 /* Magic flags to tell whats cooking on the pacing wheel */ 62 #define PACE_TMR_DELACK 0x01 /* Delayed ack timer running */ 63 #define PACE_TMR_RACK 0x02 /* RACK timer running */ 64 #define PACE_TMR_TLP 0x04 /* TLP timer running */ 65 #define PACE_TMR_RXT 0x08 /* Retransmit timer running */ 66 #define PACE_TMR_PERSIT 0x10 /* Persists timer running */ 67 #define PACE_TMR_KEEP 0x20 /* Keep alive timer running */ 68 #define PACE_PKT_OUTPUT 0x40 /* Output Packets being paced */ 69 #define PACE_TMR_MASK (PACE_TMR_KEEP|PACE_TMR_PERSIT|PACE_TMR_RXT|PACE_TMR_TLP|PACE_TMR_RACK|PACE_TMR_DELACK) 70 71 #define DEFAULT_CONNECTION_THESHOLD 100 72 73 /* 74 * When using the hpts, a TCP stack must make sure 75 * that once a INP_DROPPED flag is applied to a INP 76 * that it does not expect tcp_output() to ever be 77 * called by the hpts. The hpts will *not* call 78 * any output (or input) functions on a TCB that 79 * is in the DROPPED state. 80 * 81 * This implies final ACK's and RST's that might 82 * be sent when a TCB is still around must be 83 * sent from a routine like tcp_respond(). 84 */ 85 #define LOWEST_SLEEP_ALLOWED 50 86 #define DEFAULT_MIN_SLEEP 250 /* How many usec's is default for hpts sleep 87 * this determines min granularity of the 88 * hpts. If 1, granularity is 10useconds at 89 * the cost of more CPU (context switching). 90 * Note do not set this to 0. 91 */ 92 #define DYNAMIC_MIN_SLEEP DEFAULT_MIN_SLEEP 93 #define DYNAMIC_MAX_SLEEP 100000 /* 100ms */ 94 /* No of connections when wee start aligning to the cpu from syscalls */ 95 #define OLDEST_THRESHOLD 1200 96 /* Thresholds for raising/lowering sleep */ 97 #define TICKS_INDICATE_MORE_SLEEP 100 /* This would be 1ms */ 98 #define TICKS_INDICATE_LESS_SLEEP 1000 /* This would indicate 10ms */ 99 /** 100 * 101 * Dynamic adjustment of sleeping times is done in "new" mode 102 * where we are depending on syscall returns and lro returns 103 * to push hpts forward mainly and the timer is only a backstop. 104 * 105 * When we are in the "new" mode i.e. conn_cnt > conn_cnt_thresh 106 * then we do a dynamic adjustment on the time we sleep. 107 * Our threshold is if the lateness of the first client served (in ticks) is 108 * greater than or equal too ticks_indicate_more_sleep (10ms 109 * or 10000 ticks). If we were that late, the actual sleep time 110 * is adjusted down by 50%. If the ticks_ran is less than 111 * ticks_indicate_more_sleep (100 ticks or 1000usecs). 112 * 113 */ 114 115 116 #ifdef _KERNEL 117 #define tcp_hpts_remove(a, b) __tcp_hpts_remove(a, b, __LINE__) 118 void __tcp_hpts_remove(struct inpcb *inp, int32_t flags, int32_t line); 119 #define HPTS_REMOVE_DROPQ 0x01 120 #define HPTS_REMOVE_OUTPUT 0x02 121 #define HPTS_REMOVE_ALL (HPTS_REMOVE_DROPQ | HPTS_REMOVE_OUTPUT) 122 bool tcp_in_hpts(struct inpcb *); 123 124 /* 125 * To insert a TCB on the hpts you *must* be holding the 126 * INP_WLOCK(). The hpts insert code will then acqurire 127 * the hpts's lock and insert the TCB on the requested 128 * slot possibly waking up the hpts if you are requesting 129 * a time earlier than what the hpts is sleeping to (if 130 * the hpts is sleeping). You may check the inp->inp_in_hpts 131 * flag without the hpts lock. The hpts is the only one 132 * that will clear this flag holding only the hpts lock. This 133 * means that in your tcp_output() routine when you test for 134 * it to be 1 (so you wont call output) it may be transitioning 135 * to 0 (by the hpts). That will be fine since that will just 136 * mean an extra call to tcp_output that most likely will find 137 * the call you executed (when the mis-match occured) will have 138 * put the TCB back on the hpts and it will return. If your 139 * call did not add it back to the hpts then you will either 140 * over-send or the cwnd will block you from sending more. 141 * 142 * Note you should also be holding the INP_WLOCK() when you 143 * call the remove from the hpts as well. Thoug usually 144 * you are either doing this from a timer, where you need 145 * that INP_WLOCK() or from destroying your TCB where again 146 * you should already have the INP_WLOCK(). 147 */ 148 uint32_t tcp_hpts_insert_diag(struct inpcb *inp, uint32_t slot, int32_t line, 149 struct hpts_diag *diag); 150 #define tcp_hpts_insert(inp, slot) \ 151 tcp_hpts_insert_diag((inp), (slot), __LINE__, NULL) 152 153 void __tcp_set_hpts(struct inpcb *inp, int32_t line); 154 #define tcp_set_hpts(a) __tcp_set_hpts(a, __LINE__) 155 156 void tcp_set_inp_to_drop(struct inpcb *inp, uint16_t reason); 157 158 void tcp_run_hpts(void); 159 160 uint16_t hpts_random_cpu(struct inpcb *inp); 161 162 extern int32_t tcp_min_hptsi_time; 163 164 #endif /* _KERNEL */ 165 166 /* 167 * The following functions should also be available 168 * to userspace as well. 169 */ 170 static __inline uint32_t 171 tcp_tv_to_hptstick(const struct timeval *sv) 172 { 173 return ((sv->tv_sec * 100000) + (sv->tv_usec / HPTS_TICKS_PER_SLOT)); 174 } 175 176 static __inline uint32_t 177 tcp_tv_to_usectick(const struct timeval *sv) 178 { 179 return ((uint32_t) ((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec)); 180 } 181 182 static __inline uint32_t 183 tcp_tv_to_mssectick(const struct timeval *sv) 184 { 185 return ((uint32_t) ((sv->tv_sec * HPTS_MSEC_IN_SEC) + (sv->tv_usec/HPTS_USEC_IN_MSEC))); 186 } 187 188 static __inline uint64_t 189 tcp_tv_to_lusectick(const struct timeval *sv) 190 { 191 return ((uint64_t)((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec)); 192 } 193 194 #ifdef _KERNEL 195 static __inline uint32_t 196 tcp_gethptstick(struct timeval *sv) 197 { 198 struct timeval tv; 199 200 if (sv == NULL) 201 sv = &tv; 202 microuptime(sv); 203 return (tcp_tv_to_hptstick(sv)); 204 } 205 206 static __inline uint32_t 207 tcp_get_usecs(struct timeval *tv) 208 { 209 struct timeval tvd; 210 211 if (tv == NULL) 212 tv = &tvd; 213 microuptime(tv); 214 return (tcp_tv_to_usectick(tv)); 215 } 216 217 #endif /* _KERNEL */ 218 #endif /* __tcp_hpts_h__ */ 219