Line data Source code
1 : #ifndef HEADER_fd_src_disco_quic_fd_tpu_reasm_private_h 2 : #define HEADER_fd_src_disco_quic_fd_tpu_reasm_private_h 3 : 4 : #include "fd_tpu.h" 5 : 6 : #include <assert.h> 7 : 8 : /* fd_tpu_reasm_private.h contains reusable logic of fd_tpu_reasm such 9 : that it can be included in test cases. */ 10 : 11 0 : #define FD_TPU_REASM_MAGIC (0xb4ef0d5ea766713cUL) /* random */ 12 : 13 : /* FIXME use a doubly-linked map_chain here to optimize for fast removes */ 14 : #define MAP_NAME fd_tpu_reasm_map 15 : #define MAP_KEY_T fd_tpu_reasm_key_t 16 : #define MAP_ELE_T fd_tpu_reasm_slot_t 17 0 : #define MAP_IDX_T uint 18 0 : #define MAP_KEY k 19 0 : #define MAP_KEY_EQ(a,b) (((a)->conn_uid==(b)->conn_uid) & ((a)->stream_id==(b)->stream_id)) 20 0 : #define MAP_KEY_HASH(key,seed) fd_tpu_reasm_key_hash( key, seed ) 21 0 : #define MAP_NEXT chain_next 22 : #include "../../util/tmpl/fd_map_chain.c" 23 : 24 : /* fd_tpu_reasm_reset initializes all reassembly slots to their initial 25 : state. Corrupts messages currently visible in mcache ring. */ 26 : 27 : void 28 : fd_tpu_reasm_reset( fd_tpu_reasm_t * reasm ); 29 : 30 : static inline FD_FN_PURE fd_tpu_reasm_map_t * 31 0 : fd_tpu_reasm_map_laddr( fd_tpu_reasm_t * reasm ) { 32 0 : return (fd_tpu_reasm_map_t *)( (ulong)reasm + reasm->map_off ); 33 0 : } 34 : 35 : /* Slot class methods *************************************************/ 36 : 37 : static inline uint 38 : slot_get_idx( fd_tpu_reasm_t const * reasm, 39 0 : fd_tpu_reasm_slot_t const * slot ) { 40 0 : ulong slot_idx = (ulong)( slot - fd_tpu_reasm_slots_laddr_const( reasm ) ); 41 0 : if( FD_UNLIKELY( slot_idx >= (reasm->depth + reasm->burst) ) ) { 42 0 : FD_LOG_CRIT(( "invalid slot pointer! slot_idx=%lu, depth+burst=%u\n", 43 0 : slot_idx, reasm->depth + reasm->burst )); 44 0 : } 45 0 : return (uint)slot_idx; 46 0 : } 47 : 48 : FD_FN_CONST static inline ulong 49 0 : slot_get_offset( ulong slot_idx ) { 50 0 : return slot_idx * FD_TPU_REASM_MTU; 51 0 : } 52 : 53 : /* slot data consists of fd_txn_m_t and a variable size raw transaction 54 : payload from the network. 55 : 56 : ############### 57 : fd_txn_m_t hdr; 58 : uchar pkt_payload[]; 59 : ############### 60 : 61 : slot_get_data returns a pointer to the fd_txn_m_t header. 62 : slot_get_data_pkt_payload returns a pointer to the packet payload. 63 : */ 64 : FD_FN_PURE static inline uchar * 65 : slot_get_data( fd_tpu_reasm_t * reasm, 66 0 : ulong slot_idx ) { 67 0 : return reasm->dcache + slot_get_offset( slot_idx ); 68 0 : } 69 : 70 : FD_FN_PURE static inline uchar const * 71 : slot_get_data_const( fd_tpu_reasm_t const * reasm, 72 0 : ulong slot_idx ) { 73 0 : return reasm->dcache + slot_get_offset( slot_idx ); 74 0 : } 75 : 76 : FD_FN_PURE static inline uchar * 77 : slot_get_data_pkt_payload( fd_tpu_reasm_t * reasm, 78 0 : ulong slot_idx ) { 79 0 : return reasm->dcache + slot_get_offset( slot_idx ) + sizeof(fd_txn_m_t); 80 0 : } 81 : 82 : static FD_FN_UNUSED void 83 0 : slot_begin( fd_tpu_reasm_slot_t * slot ) { 84 0 : memset( slot, 0, sizeof(fd_tpu_reasm_slot_t) ); 85 0 : slot->k.state = FD_TPU_REASM_STATE_BUSY; 86 0 : slot->k.conn_uid = ULONG_MAX; 87 0 : slot->k.stream_id = FD_TPU_REASM_SID_MASK; 88 0 : } 89 : 90 : /* Slot queue methods ************************************************** 91 : 92 : slotq is an LRU cache implemented by a doubly linked list. 93 : tpu_reasm uses it to allocate and evict reassembly slots. */ 94 : 95 : /* slotq_push_head adds the given slot to the reassembly queue head. 96 : Assumes queue element count > 2. */ 97 : 98 : static FD_FN_UNUSED void 99 : slotq_push_head( fd_tpu_reasm_t * reasm, 100 0 : fd_tpu_reasm_slot_t * slot ) { 101 : 102 0 : uint slot_idx = slot_get_idx( reasm, slot ); 103 0 : uint head_idx = reasm->head; 104 : 105 0 : fd_tpu_reasm_slot_t * head = fd_tpu_reasm_slots_laddr( reasm ) + head_idx; 106 : 107 0 : head->lru_prev = slot_idx; 108 0 : slot->lru_prev = UINT_MAX; 109 0 : slot->lru_next = head_idx; 110 0 : reasm->head = slot_idx; 111 0 : } 112 : 113 : /* slotq_push_tail adds the given slot to the reassembly queue tail. 114 : Assumes queue element count > 2. */ 115 : 116 : static FD_FN_UNUSED void 117 : slotq_push_tail( fd_tpu_reasm_t * reasm, 118 0 : fd_tpu_reasm_slot_t * slot ) { 119 : 120 0 : uint slot_idx = slot_get_idx( reasm, slot ); 121 0 : uint tail_idx = reasm->tail; 122 0 : FD_TEST( tail_idx < reasm->slot_cnt ); 123 : 124 0 : fd_tpu_reasm_slot_t * tail = fd_tpu_reasm_slots_laddr( reasm ) + tail_idx; 125 : 126 0 : tail->lru_next = slot_idx; 127 0 : slot->lru_prev = tail_idx; 128 0 : slot->lru_next = UINT_MAX; 129 0 : reasm->tail = slot_idx; 130 0 : } 131 : 132 : /* slotq_pop_tail removes a slot from the reassembly queue tail. 133 : Assumes queue element count > 2. */ 134 : 135 : static FD_FN_UNUSED fd_tpu_reasm_slot_t * 136 0 : slotq_pop_tail( fd_tpu_reasm_t * reasm ) { 137 : 138 0 : uint tail_idx = reasm->tail; 139 0 : fd_tpu_reasm_slot_t * tail = fd_tpu_reasm_slots_laddr( reasm ) + tail_idx; 140 0 : uint slot_idx = tail->lru_prev; 141 0 : fd_tpu_reasm_slot_t * slot = fd_tpu_reasm_slots_laddr( reasm ) + slot_idx; 142 : 143 0 : slot->lru_next = UINT_MAX; 144 0 : reasm->tail = slot_idx; 145 0 : return tail; 146 0 : } 147 : 148 : /* slotq_remove removes a slot at an arbitrary position in the 149 : reassembly queue. Aborts the process if the slot is not part of the 150 : queue. Assumes queue element count > 2. */ 151 : 152 : static FD_FN_UNUSED void 153 : slotq_remove( fd_tpu_reasm_t * reasm, 154 0 : fd_tpu_reasm_slot_t * slot ) { 155 : 156 0 : uint slot_idx = slot_get_idx( reasm, slot ); 157 0 : uint lru_prev = slot->lru_prev; 158 0 : uint lru_next = slot->lru_next; 159 : 160 0 : slot->lru_prev = UINT_MAX; 161 0 : slot->lru_next = UINT_MAX; 162 : 163 0 : fd_tpu_reasm_slot_t * prev = fd_tpu_reasm_slots_laddr( reasm ) + lru_prev; 164 0 : fd_tpu_reasm_slot_t * next = fd_tpu_reasm_slots_laddr( reasm ) + lru_next; 165 : 166 0 : if( slot_idx==reasm->head ) { 167 0 : if( FD_UNLIKELY( lru_next >= reasm->slot_cnt ) ) { 168 0 : FD_LOG_ERR(( "OOB lru_next (lru_next=%u, slot_cnt=%u)", lru_next, reasm->slot_cnt )); 169 0 : } 170 0 : reasm->head = lru_next; 171 0 : next->lru_prev = UINT_MAX; 172 0 : return; 173 0 : } 174 0 : if( slot_idx==reasm->tail ) { 175 0 : if( FD_UNLIKELY( lru_prev >= reasm->slot_cnt ) ) { 176 0 : FD_LOG_ERR(( "OOB lru_prev (lru_prev=%u, slot_cnt=%u)", lru_prev, reasm->slot_cnt )); 177 0 : } 178 0 : reasm->tail = lru_prev; 179 0 : prev->lru_next = UINT_MAX; 180 0 : return; 181 0 : } 182 : 183 0 : assert( lru_prev < reasm->slot_cnt ); 184 0 : assert( lru_next < reasm->slot_cnt ); 185 0 : if( FD_UNLIKELY( lru_prev >= reasm->slot_cnt ) ) { 186 0 : FD_LOG_ERR(( "OOB lru_prev (lru_prev=%u, slot_cnt=%u)", lru_prev, reasm->slot_cnt )); 187 0 : } 188 0 : if( FD_UNLIKELY( lru_next >= reasm->slot_cnt ) ) { 189 0 : FD_LOG_ERR(( "OOB lru_next (lru_next=%u, slot_cnt=%u)", lru_next, reasm->slot_cnt )); 190 0 : } 191 0 : prev->lru_next = lru_next; 192 0 : next->lru_prev = lru_prev; 193 0 : } 194 : 195 : static FD_FN_UNUSED void 196 : smap_insert( fd_tpu_reasm_t * reasm, 197 0 : fd_tpu_reasm_slot_t * slot ) { 198 0 : fd_tpu_reasm_map_ele_insert( 199 0 : fd_tpu_reasm_map_laddr( reasm ), 200 0 : slot, 201 0 : fd_tpu_reasm_slots_laddr( reasm ) 202 0 : ); 203 0 : } 204 : 205 : static FD_FN_UNUSED fd_tpu_reasm_slot_t * 206 : smap_query( fd_tpu_reasm_t * reasm, 207 : ulong conn_uid, 208 0 : ulong stream_id ) { 209 0 : fd_tpu_reasm_key_t k = { 210 0 : .conn_uid = conn_uid, 211 0 : .stream_id = stream_id & FD_TPU_REASM_SID_MASK 212 0 : }; 213 0 : return fd_tpu_reasm_map_ele_query( 214 0 : fd_tpu_reasm_map_laddr( reasm ), 215 0 : &k, 216 0 : NULL, 217 0 : fd_tpu_reasm_slots_laddr( reasm ) 218 0 : ); 219 0 : } 220 : 221 : static FD_FN_UNUSED void 222 : smap_remove( fd_tpu_reasm_t * reasm, 223 0 : fd_tpu_reasm_slot_t * slot ) { 224 : /* FIXME use a doubly linked list remove */ 225 0 : fd_tpu_reasm_map_idx_remove( 226 0 : fd_tpu_reasm_map_laddr( reasm ), 227 0 : &slot->k, 228 0 : ULONG_MAX, 229 0 : fd_tpu_reasm_slots_laddr( reasm ) 230 0 : ); 231 0 : } 232 : 233 : #endif /* HEADER_fd_src_disco_quic_fd_tpu_reasm_private_h */