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 5000 /* 5ms */ 94 95 /* Thresholds for raising/lowering sleep */ 96 #define TICKS_INDICATE_MORE_SLEEP 100 /* This would be 1ms */ 97 #define TICKS_INDICATE_LESS_SLEEP 1000 /* This would indicate 10ms */ 98 /** 99 * 100 * Dynamic adjustment of sleeping times is done in "new" mode 101 * where we are depending on syscall returns and lro returns 102 * to push hpts forward mainly and the timer is only a backstop. 103 * 104 * When we are in the "new" mode i.e. conn_cnt > conn_cnt_thresh 105 * then we do a dynamic adjustment on the time we sleep. 106 * Our threshold is if the lateness of the first client served (in ticks) is 107 * greater than or equal too ticks_indicate_more_sleep (10ms 108 * or 10000 ticks). If we were that late, the actual sleep time 109 * is adjusted down by 50%. If the ticks_ran is less than 110 * ticks_indicate_more_sleep (100 ticks or 1000usecs). 111 * 112 */ 113 114 115 #ifdef _KERNEL 116 void tcp_hpts_remove(struct inpcb *); 117 bool tcp_in_hpts(struct inpcb *); 118 119 /* 120 * To insert a TCB on the hpts you *must* be holding the 121 * INP_WLOCK(). The hpts insert code will then acqurire 122 * the hpts's lock and insert the TCB on the requested 123 * slot possibly waking up the hpts if you are requesting 124 * a time earlier than what the hpts is sleeping to (if 125 * the hpts is sleeping). You may check the inp->inp_in_hpts 126 * flag without the hpts lock. The hpts is the only one 127 * that will clear this flag holding only the hpts lock. This 128 * means that in your tcp_output() routine when you test for 129 * it to be 1 (so you wont call output) it may be transitioning 130 * to 0 (by the hpts). That will be fine since that will just 131 * mean an extra call to tcp_output that most likely will find 132 * the call you executed (when the mis-match occurred) will have 133 * put the TCB back on the hpts and it will return. If your 134 * call did not add it back to the hpts then you will either 135 * over-send or the cwnd will block you from sending more. 136 * 137 * Note you should also be holding the INP_WLOCK() when you 138 * call the remove from the hpts as well. Thoug usually 139 * you are either doing this from a timer, where you need 140 * that INP_WLOCK() or from destroying your TCB where again 141 * you should already have the INP_WLOCK(). 142 */ 143 uint32_t tcp_hpts_insert_diag(struct inpcb *inp, uint32_t slot, int32_t line, 144 struct hpts_diag *diag); 145 #define tcp_hpts_insert(inp, slot) \ 146 tcp_hpts_insert_diag((inp), (slot), __LINE__, NULL) 147 148 void __tcp_set_hpts(struct inpcb *inp, int32_t line); 149 #define tcp_set_hpts(a) __tcp_set_hpts(a, __LINE__) 150 151 void tcp_set_inp_to_drop(struct inpcb *inp, uint16_t reason); 152 153 void tcp_run_hpts(void); 154 155 uint16_t hpts_random_cpu(struct inpcb *inp); 156 157 extern int32_t tcp_min_hptsi_time; 158 159 #endif /* _KERNEL */ 160 161 /* 162 * The following functions should also be available 163 * to userspace as well. 164 */ 165 static __inline uint32_t 166 tcp_tv_to_hptstick(const struct timeval *sv) 167 { 168 return ((sv->tv_sec * 100000) + (sv->tv_usec / HPTS_TICKS_PER_SLOT)); 169 } 170 171 static __inline uint32_t 172 tcp_tv_to_usectick(const struct timeval *sv) 173 { 174 return ((uint32_t) ((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec)); 175 } 176 177 static __inline uint32_t 178 tcp_tv_to_mssectick(const struct timeval *sv) 179 { 180 return ((uint32_t) ((sv->tv_sec * HPTS_MSEC_IN_SEC) + (sv->tv_usec/HPTS_USEC_IN_MSEC))); 181 } 182 183 static __inline uint64_t 184 tcp_tv_to_lusectick(const struct timeval *sv) 185 { 186 return ((uint64_t)((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec)); 187 } 188 189 #ifdef _KERNEL 190 static __inline uint32_t 191 tcp_gethptstick(struct timeval *sv) 192 { 193 struct timeval tv; 194 195 if (sv == NULL) 196 sv = &tv; 197 microuptime(sv); 198 return (tcp_tv_to_hptstick(sv)); 199 } 200 201 static __inline uint32_t 202 tcp_get_usecs(struct timeval *tv) 203 { 204 struct timeval tvd; 205 206 if (tv == NULL) 207 tv = &tvd; 208 microuptime(tv); 209 return (tcp_tv_to_usectick(tv)); 210 } 211 212 #endif /* _KERNEL */ 213 #endif /* __tcp_hpts_h__ */ 214