1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <pthread.h> 4 #include "addr_pool.h" 5 #include "util.h" 6 #include "debug.h" 7 #include "config.h" 8 9 #define MIN_PORT (1025) 10 #define MAX_PORT (65535 + 1) 11 12 /*----------------------------------------------------------------------------*/ 13 struct addr_entry 14 { 15 struct sockaddr_in addr; 16 TAILQ_ENTRY(addr_entry) addr_link; 17 }; 18 /*----------------------------------------------------------------------------*/ 19 struct addr_map 20 { 21 struct addr_entry *addrmap[MAX_PORT]; 22 }; 23 /*----------------------------------------------------------------------------*/ 24 struct addr_pool 25 { 26 struct addr_entry *pool; /* address pool */ 27 struct addr_map *mapper; /* address map */ 28 29 uint32_t addr_base; /* in host order */ 30 int num_addr; /* number of addresses in use */ 31 32 int num_entry; 33 int num_free; 34 int num_used; 35 36 pthread_mutex_t lock; 37 TAILQ_HEAD(, addr_entry) free_list; 38 TAILQ_HEAD(, addr_entry) used_list; 39 }; 40 /*----------------------------------------------------------------------------*/ 41 addr_pool_t 42 CreateAddressPool(in_addr_t addr_base, int num_addr) 43 { 44 struct addr_pool *ap; 45 int num_entry; 46 int i, j, cnt; 47 in_addr_t addr; 48 uint32_t addr_h; 49 50 ap = (addr_pool_t)calloc(1, sizeof(struct addr_pool)); 51 if (!ap) 52 return NULL; 53 54 /* initialize address pool */ 55 num_entry = num_addr * (MAX_PORT - MIN_PORT); 56 ap->pool = (struct addr_entry *)calloc(num_entry, sizeof(struct addr_entry)); 57 if (!ap->pool) { 58 free(ap); 59 return NULL; 60 } 61 62 /* initialize address map */ 63 ap->mapper = (struct addr_map *)calloc(num_addr, sizeof(struct addr_map)); 64 if (!ap->mapper) { 65 free(ap->pool); 66 free(ap); 67 return NULL; 68 } 69 70 TAILQ_INIT(&ap->free_list); 71 TAILQ_INIT(&ap->used_list); 72 73 if (pthread_mutex_init(&ap->lock, NULL)) { 74 free(ap->pool); 75 free(ap); 76 return NULL; 77 } 78 79 pthread_mutex_lock(&ap->lock); 80 81 ap->addr_base = ntohl(addr_base); 82 ap->num_addr = num_addr; 83 84 cnt = 0; 85 for (i = 0; i < num_addr; i++) { 86 addr_h = ap->addr_base + i; 87 addr = htonl(addr_h); 88 for (j = MIN_PORT; j < MAX_PORT; j++) { 89 ap->pool[cnt].addr.sin_addr.s_addr = addr; 90 ap->pool[cnt].addr.sin_port = htons(j); 91 ap->mapper[i].addrmap[j] = &ap->pool[cnt]; 92 93 TAILQ_INSERT_TAIL(&ap->free_list, &ap->pool[cnt], addr_link); 94 95 if ((++cnt) >= num_entry) 96 break; 97 } 98 } 99 ap->num_entry = cnt; 100 ap->num_free = cnt; 101 ap->num_used = 0; 102 103 pthread_mutex_unlock(&ap->lock); 104 105 return ap; 106 } 107 /*----------------------------------------------------------------------------*/ 108 addr_pool_t 109 CreateAddressPoolPerCore(int core, int num_queues, 110 in_addr_t saddr_base, int num_addr, in_addr_t daddr, in_port_t dport) 111 { 112 struct addr_pool *ap; 113 int num_entry; 114 int i, j, cnt, endian_check; 115 in_addr_t saddr; 116 uint32_t saddr_h, daddr_h; 117 uint16_t sport_h, dport_h; 118 int rss_core; 119 120 ap = (addr_pool_t)calloc(1, sizeof(struct addr_pool)); 121 if (!ap) 122 return NULL; 123 124 /* initialize address pool */ 125 num_entry = (num_addr * (MAX_PORT - MIN_PORT)) / num_queues; 126 ap->pool = (struct addr_entry *)calloc(num_entry, sizeof(struct addr_entry)); 127 if (!ap->pool) { 128 free(ap); 129 return NULL; 130 } 131 132 /* initialize address map */ 133 ap->mapper = (struct addr_map *)calloc(num_addr, sizeof(struct addr_map)); 134 if (!ap->mapper) { 135 free(ap->pool); 136 free(ap); 137 return NULL; 138 } 139 140 TAILQ_INIT(&ap->free_list); 141 TAILQ_INIT(&ap->used_list); 142 143 if (pthread_mutex_init(&ap->lock, NULL)) { 144 free(ap->pool); 145 free(ap); 146 return NULL; 147 } 148 149 endian_check = FetchEndianType(); 150 pthread_mutex_lock(&ap->lock); 151 152 ap->addr_base = ntohl(saddr_base); 153 ap->num_addr = num_addr; 154 daddr_h = ntohl(daddr); 155 dport_h = ntohs(dport); 156 157 /* search address space to get RSS-friendly addresses */ 158 cnt = 0; 159 for (i = 0; i < num_addr; i++) { 160 saddr_h = ap->addr_base + i; 161 saddr = htonl(saddr_h); 162 for (j = MIN_PORT; j < MAX_PORT; j++) { 163 if (cnt >= num_entry) 164 break; 165 166 sport_h = j; 167 rss_core = GetRSSCPUCore(daddr_h, saddr_h, dport_h, sport_h, 168 num_queues, endian_check); 169 if (rss_core != core) 170 continue; 171 172 ap->pool[cnt].addr.sin_addr.s_addr = saddr; 173 ap->pool[cnt].addr.sin_port = htons(sport_h); 174 ap->mapper[i].addrmap[j] = &ap->pool[cnt]; 175 TAILQ_INSERT_TAIL(&ap->free_list, &ap->pool[cnt], addr_link); 176 cnt++; 177 } 178 } 179 180 ap->num_entry = cnt; 181 ap->num_free = cnt; 182 ap->num_used = 0; 183 //fprintf(stderr, "CPU %d: Created %d address entries.\n", core, cnt); 184 if (ap->num_entry < g_config.mos->max_concurrency) { 185 fprintf(stderr, "[WARINING] Available # addresses (%d) is smaller than" 186 " the max concurrency (%d).\n", 187 ap->num_entry, g_config.mos->max_concurrency); 188 } 189 190 pthread_mutex_unlock(&ap->lock); 191 192 return ap; 193 } 194 /*----------------------------------------------------------------------------*/ 195 void 196 DestroyAddressPool(addr_pool_t ap) 197 { 198 if (!ap) 199 return; 200 201 if (ap->pool) { 202 free(ap->pool); 203 ap->pool = NULL; 204 } 205 206 if (ap->mapper) { 207 free(ap->mapper); 208 ap->mapper = NULL; 209 } 210 211 pthread_mutex_destroy(&ap->lock); 212 213 free(ap); 214 } 215 /*----------------------------------------------------------------------------*/ 216 int 217 FetchAddress(addr_pool_t ap, int core, int num_queues, 218 const struct sockaddr_in *daddr, struct sockaddr_in *saddr) 219 { 220 struct addr_entry *walk, *next; 221 int rss_core, endian_check; 222 int ret = -1; 223 224 if (!ap || !daddr || !saddr) 225 return -1; 226 227 endian_check = FetchEndianType(); 228 pthread_mutex_lock(&ap->lock); 229 230 walk = TAILQ_FIRST(&ap->free_list); 231 while (walk) { 232 next = TAILQ_NEXT(walk, addr_link); 233 234 if (saddr->sin_addr.s_addr != INADDR_ANY && 235 walk->addr.sin_addr.s_addr != saddr->sin_addr.s_addr) { 236 walk = next; 237 continue; 238 } 239 240 if (saddr->sin_port != INPORT_ANY && 241 walk->addr.sin_port != saddr->sin_port) { 242 walk = next; 243 continue; 244 } 245 246 rss_core = GetRSSCPUCore(ntohl(walk->addr.sin_addr.s_addr), 247 ntohl(daddr->sin_addr.s_addr), ntohs(walk->addr.sin_port), 248 ntohs(daddr->sin_port), num_queues, endian_check); 249 250 if (core == rss_core) 251 break; 252 253 walk = next; 254 } 255 256 if (walk) { 257 *saddr = walk->addr; 258 TAILQ_REMOVE(&ap->free_list, walk, addr_link); 259 TAILQ_INSERT_TAIL(&ap->used_list, walk, addr_link); 260 ap->num_free--; 261 ap->num_used++; 262 ret = 0; 263 } 264 265 pthread_mutex_unlock(&ap->lock); 266 267 return ret; 268 } 269 /*----------------------------------------------------------------------------*/ 270 int 271 FetchAddressPerCore(addr_pool_t ap, int core, int num_queues, 272 const struct sockaddr_in *daddr, struct sockaddr_in *saddr) 273 { 274 struct addr_entry *walk; 275 int ret = -1; 276 277 if (!ap || !daddr || !saddr) 278 return -1; 279 280 pthread_mutex_lock(&ap->lock); 281 282 /* we don't need to calculate RSSCPUCore if mtcp_init_rss is called */ 283 walk = TAILQ_FIRST(&ap->free_list); 284 if (walk) { 285 *saddr = walk->addr; 286 TAILQ_REMOVE(&ap->free_list, walk, addr_link); 287 TAILQ_INSERT_TAIL(&ap->used_list, walk, addr_link); 288 ap->num_free--; 289 ap->num_used++; 290 ret = 0; 291 } 292 293 pthread_mutex_unlock(&ap->lock); 294 295 return ret; 296 } 297 /*----------------------------------------------------------------------------*/ 298 int 299 FreeAddress(addr_pool_t ap, const struct sockaddr_in *addr) 300 { 301 struct addr_entry *walk, *next; 302 int ret = -1; 303 304 if (!ap || !addr) 305 return -1; 306 307 pthread_mutex_lock(&ap->lock); 308 309 if (ap->mapper) { 310 uint32_t addr_h = ntohl(addr->sin_addr.s_addr); 311 uint16_t port_h = ntohs(addr->sin_port); 312 int index = addr_h - ap->addr_base; 313 314 if (index >= 0 && index < ap->num_addr) { 315 walk = ap->mapper[addr_h - ap->addr_base].addrmap[port_h]; 316 } else { 317 walk = NULL; 318 } 319 320 } else { 321 walk = TAILQ_FIRST(&ap->used_list); 322 while (walk) { 323 next = TAILQ_NEXT(walk, addr_link); 324 if (addr->sin_port == walk->addr.sin_port && 325 addr->sin_addr.s_addr == walk->addr.sin_addr.s_addr) { 326 break; 327 } 328 329 walk = next; 330 } 331 332 } 333 334 if (walk) { 335 TAILQ_REMOVE(&ap->used_list, walk, addr_link); 336 TAILQ_INSERT_TAIL(&ap->free_list, walk, addr_link); 337 ap->num_free++; 338 ap->num_used--; 339 ret = 0; 340 } 341 342 pthread_mutex_unlock(&ap->lock); 343 344 return ret; 345 } 346 /*----------------------------------------------------------------------------*/ 347