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 #ifdef _KERNEL 115 void tcp_hpts_init(struct tcpcb *); 116 void tcp_hpts_remove(struct tcpcb *); 117 static inline bool 118 tcp_in_hpts(struct tcpcb *tp) 119 { 120 return (tp->t_in_hpts == IHPTS_ONQUEUE); 121 } 122 123 /* 124 * To insert a TCB on the hpts you *must* be holding the 125 * INP_WLOCK(). The hpts insert code will then acqurire 126 * the hpts's lock and insert the TCB on the requested 127 * slot possibly waking up the hpts if you are requesting 128 * a time earlier than what the hpts is sleeping to (if 129 * the hpts is sleeping). You may check the inp->inp_in_hpts 130 * flag without the hpts lock. The hpts is the only one 131 * that will clear this flag holding only the hpts lock. This 132 * means that in your tcp_output() routine when you test for 133 * it to be 1 (so you wont call output) it may be transitioning 134 * to 0 (by the hpts). That will be fine since that will just 135 * mean an extra call to tcp_output that most likely will find 136 * the call you executed (when the mis-match occurred) will have 137 * put the TCB back on the hpts and it will return. If your 138 * call did not add it back to the hpts then you will either 139 * over-send or the cwnd will block you from sending more. 140 * 141 * Note you should also be holding the INP_WLOCK() when you 142 * call the remove from the hpts as well. Thoug usually 143 * you are either doing this from a timer, where you need 144 * that INP_WLOCK() or from destroying your TCB where again 145 * you should already have the INP_WLOCK(). 146 */ 147 uint32_t tcp_hpts_insert_diag(struct tcpcb *tp, uint32_t slot, int32_t line, 148 struct hpts_diag *diag); 149 #define tcp_hpts_insert(inp, slot) \ 150 tcp_hpts_insert_diag((inp), (slot), __LINE__, NULL) 151 152 void __tcp_set_hpts(struct tcpcb *tp, int32_t line); 153 #define tcp_set_hpts(a) __tcp_set_hpts(a, __LINE__) 154 155 void tcp_set_inp_to_drop(struct inpcb *inp, uint16_t reason); 156 157 void tcp_run_hpts(void); 158 159 extern int32_t tcp_min_hptsi_time; 160 161 #endif /* _KERNEL */ 162 163 /* 164 * The following functions should also be available 165 * to userspace as well. 166 */ 167 static __inline uint32_t 168 tcp_tv_to_hptstick(const struct timeval *sv) 169 { 170 return ((sv->tv_sec * 100000) + (sv->tv_usec / HPTS_TICKS_PER_SLOT)); 171 } 172 173 static __inline uint32_t 174 tcp_tv_to_usectick(const struct timeval *sv) 175 { 176 return ((uint32_t) ((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec)); 177 } 178 179 static __inline uint32_t 180 tcp_tv_to_mssectick(const struct timeval *sv) 181 { 182 return ((uint32_t) ((sv->tv_sec * HPTS_MSEC_IN_SEC) + (sv->tv_usec/HPTS_USEC_IN_MSEC))); 183 } 184 185 static __inline uint64_t 186 tcp_tv_to_lusectick(const struct timeval *sv) 187 { 188 return ((uint64_t)((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec)); 189 } 190 191 #ifdef _KERNEL 192 193 extern int32_t tcp_min_hptsi_time; 194 195 __inline int32_t 196 get_hpts_min_sleep_time(void) 197 { 198 return (tcp_min_hptsi_time + HPTS_TICKS_PER_SLOT); 199 } 200 201 static __inline uint32_t 202 tcp_gethptstick(struct timeval *sv) 203 { 204 struct timeval tv; 205 206 if (sv == NULL) 207 sv = &tv; 208 microuptime(sv); 209 return (tcp_tv_to_hptstick(sv)); 210 } 211 212 static __inline uint32_t 213 tcp_get_usecs(struct timeval *tv) 214 { 215 struct timeval tvd; 216 217 if (tv == NULL) 218 tv = &tvd; 219 microuptime(tv); 220 return (tcp_tv_to_usectick(tv)); 221 } 222 223 #endif /* _KERNEL */ 224 #endif /* __tcp_hpts_h__ */ 225