176404edcSAsim Jamshed #include <stdio.h> 276404edcSAsim Jamshed #include <stdlib.h> 376404edcSAsim Jamshed #include <pthread.h> 476404edcSAsim Jamshed #include "addr_pool.h" 5152f7c19SAsim Jamshed #include "util.h" 676404edcSAsim Jamshed #include "debug.h" 776404edcSAsim Jamshed #include "config.h" 876404edcSAsim Jamshed 976404edcSAsim Jamshed #define MIN_PORT (1025) 1076404edcSAsim Jamshed #define MAX_PORT (65535 + 1) 1176404edcSAsim Jamshed 1276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 1376404edcSAsim Jamshed struct addr_entry 1476404edcSAsim Jamshed { 1576404edcSAsim Jamshed struct sockaddr_in addr; 1676404edcSAsim Jamshed TAILQ_ENTRY(addr_entry) addr_link; 1776404edcSAsim Jamshed }; 1876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 1976404edcSAsim Jamshed struct addr_map 2076404edcSAsim Jamshed { 2176404edcSAsim Jamshed struct addr_entry *addrmap[MAX_PORT]; 2276404edcSAsim Jamshed }; 2376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 2476404edcSAsim Jamshed struct addr_pool 2576404edcSAsim Jamshed { 2676404edcSAsim Jamshed struct addr_entry *pool; /* address pool */ 2776404edcSAsim Jamshed struct addr_map *mapper; /* address map */ 2876404edcSAsim Jamshed 2976404edcSAsim Jamshed uint32_t addr_base; /* in host order */ 3076404edcSAsim Jamshed int num_addr; /* number of addresses in use */ 3176404edcSAsim Jamshed 3276404edcSAsim Jamshed int num_entry; 3376404edcSAsim Jamshed int num_free; 3476404edcSAsim Jamshed int num_used; 3576404edcSAsim Jamshed 3676404edcSAsim Jamshed pthread_mutex_t lock; 3776404edcSAsim Jamshed TAILQ_HEAD(, addr_entry) free_list; 3876404edcSAsim Jamshed TAILQ_HEAD(, addr_entry) used_list; 3976404edcSAsim Jamshed }; 4076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 4176404edcSAsim Jamshed addr_pool_t 4276404edcSAsim Jamshed CreateAddressPool(in_addr_t addr_base, int num_addr) 4376404edcSAsim Jamshed { 4476404edcSAsim Jamshed struct addr_pool *ap; 4576404edcSAsim Jamshed int num_entry; 4676404edcSAsim Jamshed int i, j, cnt; 4776404edcSAsim Jamshed in_addr_t addr; 4876404edcSAsim Jamshed uint32_t addr_h; 4976404edcSAsim Jamshed 5076404edcSAsim Jamshed ap = (addr_pool_t)calloc(1, sizeof(struct addr_pool)); 5176404edcSAsim Jamshed if (!ap) 5276404edcSAsim Jamshed return NULL; 5376404edcSAsim Jamshed 5476404edcSAsim Jamshed /* initialize address pool */ 5576404edcSAsim Jamshed num_entry = num_addr * (MAX_PORT - MIN_PORT); 5676404edcSAsim Jamshed ap->pool = (struct addr_entry *)calloc(num_entry, sizeof(struct addr_entry)); 5776404edcSAsim Jamshed if (!ap->pool) { 5876404edcSAsim Jamshed free(ap); 5976404edcSAsim Jamshed return NULL; 6076404edcSAsim Jamshed } 6176404edcSAsim Jamshed 6276404edcSAsim Jamshed /* initialize address map */ 6376404edcSAsim Jamshed ap->mapper = (struct addr_map *)calloc(num_addr, sizeof(struct addr_map)); 6476404edcSAsim Jamshed if (!ap->mapper) { 6576404edcSAsim Jamshed free(ap->pool); 6676404edcSAsim Jamshed free(ap); 6776404edcSAsim Jamshed return NULL; 6876404edcSAsim Jamshed } 6976404edcSAsim Jamshed 7076404edcSAsim Jamshed TAILQ_INIT(&ap->free_list); 7176404edcSAsim Jamshed TAILQ_INIT(&ap->used_list); 7276404edcSAsim Jamshed 7376404edcSAsim Jamshed if (pthread_mutex_init(&ap->lock, NULL)) { 7476404edcSAsim Jamshed free(ap->pool); 7576404edcSAsim Jamshed free(ap); 7676404edcSAsim Jamshed return NULL; 7776404edcSAsim Jamshed } 7876404edcSAsim Jamshed 7976404edcSAsim Jamshed pthread_mutex_lock(&ap->lock); 8076404edcSAsim Jamshed 8176404edcSAsim Jamshed ap->addr_base = ntohl(addr_base); 8276404edcSAsim Jamshed ap->num_addr = num_addr; 8376404edcSAsim Jamshed 8476404edcSAsim Jamshed cnt = 0; 8576404edcSAsim Jamshed for (i = 0; i < num_addr; i++) { 8676404edcSAsim Jamshed addr_h = ap->addr_base + i; 8776404edcSAsim Jamshed addr = htonl(addr_h); 8876404edcSAsim Jamshed for (j = MIN_PORT; j < MAX_PORT; j++) { 8976404edcSAsim Jamshed ap->pool[cnt].addr.sin_addr.s_addr = addr; 9076404edcSAsim Jamshed ap->pool[cnt].addr.sin_port = htons(j); 9176404edcSAsim Jamshed ap->mapper[i].addrmap[j] = &ap->pool[cnt]; 9276404edcSAsim Jamshed 9376404edcSAsim Jamshed TAILQ_INSERT_TAIL(&ap->free_list, &ap->pool[cnt], addr_link); 9476404edcSAsim Jamshed 9576404edcSAsim Jamshed if ((++cnt) >= num_entry) 9676404edcSAsim Jamshed break; 9776404edcSAsim Jamshed } 9876404edcSAsim Jamshed } 9976404edcSAsim Jamshed ap->num_entry = cnt; 10076404edcSAsim Jamshed ap->num_free = cnt; 10176404edcSAsim Jamshed ap->num_used = 0; 10276404edcSAsim Jamshed 10376404edcSAsim Jamshed pthread_mutex_unlock(&ap->lock); 10476404edcSAsim Jamshed 10576404edcSAsim Jamshed return ap; 10676404edcSAsim Jamshed } 10776404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 10876404edcSAsim Jamshed addr_pool_t 10976404edcSAsim Jamshed CreateAddressPoolPerCore(int core, int num_queues, 11076404edcSAsim Jamshed in_addr_t saddr_base, int num_addr, in_addr_t daddr, in_port_t dport) 11176404edcSAsim Jamshed { 11276404edcSAsim Jamshed struct addr_pool *ap; 11376404edcSAsim Jamshed int num_entry; 114b88bd7d2SAsim Jamshed int i, j, cnt, endian_check; 11576404edcSAsim Jamshed in_addr_t saddr; 11676404edcSAsim Jamshed uint32_t saddr_h, daddr_h; 11776404edcSAsim Jamshed uint16_t sport_h, dport_h; 11876404edcSAsim Jamshed int rss_core; 11976404edcSAsim Jamshed 12076404edcSAsim Jamshed ap = (addr_pool_t)calloc(1, sizeof(struct addr_pool)); 12176404edcSAsim Jamshed if (!ap) 12276404edcSAsim Jamshed return NULL; 12376404edcSAsim Jamshed 12476404edcSAsim Jamshed /* initialize address pool */ 12576404edcSAsim Jamshed num_entry = (num_addr * (MAX_PORT - MIN_PORT)) / num_queues; 12676404edcSAsim Jamshed ap->pool = (struct addr_entry *)calloc(num_entry, sizeof(struct addr_entry)); 12776404edcSAsim Jamshed if (!ap->pool) { 12876404edcSAsim Jamshed free(ap); 12976404edcSAsim Jamshed return NULL; 13076404edcSAsim Jamshed } 13176404edcSAsim Jamshed 13276404edcSAsim Jamshed /* initialize address map */ 13376404edcSAsim Jamshed ap->mapper = (struct addr_map *)calloc(num_addr, sizeof(struct addr_map)); 13476404edcSAsim Jamshed if (!ap->mapper) { 13576404edcSAsim Jamshed free(ap->pool); 13676404edcSAsim Jamshed free(ap); 13776404edcSAsim Jamshed return NULL; 13876404edcSAsim Jamshed } 13976404edcSAsim Jamshed 14076404edcSAsim Jamshed TAILQ_INIT(&ap->free_list); 14176404edcSAsim Jamshed TAILQ_INIT(&ap->used_list); 14276404edcSAsim Jamshed 14376404edcSAsim Jamshed if (pthread_mutex_init(&ap->lock, NULL)) { 14476404edcSAsim Jamshed free(ap->pool); 14576404edcSAsim Jamshed free(ap); 14676404edcSAsim Jamshed return NULL; 14776404edcSAsim Jamshed } 14876404edcSAsim Jamshed 149b88bd7d2SAsim Jamshed endian_check = FetchEndianType(); 15076404edcSAsim Jamshed pthread_mutex_lock(&ap->lock); 15176404edcSAsim Jamshed 15276404edcSAsim Jamshed ap->addr_base = ntohl(saddr_base); 15376404edcSAsim Jamshed ap->num_addr = num_addr; 15476404edcSAsim Jamshed daddr_h = ntohl(daddr); 15576404edcSAsim Jamshed dport_h = ntohs(dport); 15676404edcSAsim Jamshed 15776404edcSAsim Jamshed /* search address space to get RSS-friendly addresses */ 15876404edcSAsim Jamshed cnt = 0; 15976404edcSAsim Jamshed for (i = 0; i < num_addr; i++) { 16076404edcSAsim Jamshed saddr_h = ap->addr_base + i; 16176404edcSAsim Jamshed saddr = htonl(saddr_h); 16276404edcSAsim Jamshed for (j = MIN_PORT; j < MAX_PORT; j++) { 16376404edcSAsim Jamshed if (cnt >= num_entry) 16476404edcSAsim Jamshed break; 16576404edcSAsim Jamshed 16676404edcSAsim Jamshed sport_h = j; 167b88bd7d2SAsim Jamshed rss_core = GetRSSCPUCore(daddr_h, saddr_h, dport_h, sport_h, 168b88bd7d2SAsim Jamshed num_queues, endian_check); 16976404edcSAsim Jamshed if (rss_core != core) 17076404edcSAsim Jamshed continue; 17176404edcSAsim Jamshed 17276404edcSAsim Jamshed ap->pool[cnt].addr.sin_addr.s_addr = saddr; 17376404edcSAsim Jamshed ap->pool[cnt].addr.sin_port = htons(sport_h); 17476404edcSAsim Jamshed ap->mapper[i].addrmap[j] = &ap->pool[cnt]; 17576404edcSAsim Jamshed TAILQ_INSERT_TAIL(&ap->free_list, &ap->pool[cnt], addr_link); 17676404edcSAsim Jamshed cnt++; 17776404edcSAsim Jamshed } 17876404edcSAsim Jamshed } 17976404edcSAsim Jamshed 18076404edcSAsim Jamshed ap->num_entry = cnt; 18176404edcSAsim Jamshed ap->num_free = cnt; 18276404edcSAsim Jamshed ap->num_used = 0; 18376404edcSAsim Jamshed //fprintf(stderr, "CPU %d: Created %d address entries.\n", core, cnt); 18476404edcSAsim Jamshed if (ap->num_entry < g_config.mos->max_concurrency) { 18576404edcSAsim Jamshed fprintf(stderr, "[WARINING] Available # addresses (%d) is smaller than" 18676404edcSAsim Jamshed " the max concurrency (%d).\n", 18776404edcSAsim Jamshed ap->num_entry, g_config.mos->max_concurrency); 18876404edcSAsim Jamshed } 18976404edcSAsim Jamshed 19076404edcSAsim Jamshed pthread_mutex_unlock(&ap->lock); 19176404edcSAsim Jamshed 19276404edcSAsim Jamshed return ap; 19376404edcSAsim Jamshed } 19476404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 19576404edcSAsim Jamshed void 19676404edcSAsim Jamshed DestroyAddressPool(addr_pool_t ap) 19776404edcSAsim Jamshed { 19876404edcSAsim Jamshed if (!ap) 19976404edcSAsim Jamshed return; 20076404edcSAsim Jamshed 20176404edcSAsim Jamshed if (ap->pool) { 20276404edcSAsim Jamshed free(ap->pool); 20376404edcSAsim Jamshed ap->pool = NULL; 20476404edcSAsim Jamshed } 20576404edcSAsim Jamshed 20676404edcSAsim Jamshed if (ap->mapper) { 20776404edcSAsim Jamshed free(ap->mapper); 20876404edcSAsim Jamshed ap->mapper = NULL; 20976404edcSAsim Jamshed } 21076404edcSAsim Jamshed 21176404edcSAsim Jamshed pthread_mutex_destroy(&ap->lock); 21276404edcSAsim Jamshed 21376404edcSAsim Jamshed free(ap); 21476404edcSAsim Jamshed } 21576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 21676404edcSAsim Jamshed int 21776404edcSAsim Jamshed FetchAddress(addr_pool_t ap, int core, int num_queues, 21876404edcSAsim Jamshed const struct sockaddr_in *daddr, struct sockaddr_in *saddr) 21976404edcSAsim Jamshed { 22076404edcSAsim Jamshed struct addr_entry *walk, *next; 221b88bd7d2SAsim Jamshed int rss_core, endian_check; 22276404edcSAsim Jamshed int ret = -1; 22376404edcSAsim Jamshed 22476404edcSAsim Jamshed if (!ap || !daddr || !saddr) 22576404edcSAsim Jamshed return -1; 22676404edcSAsim Jamshed 227b88bd7d2SAsim Jamshed endian_check = FetchEndianType(); 22876404edcSAsim Jamshed pthread_mutex_lock(&ap->lock); 22976404edcSAsim Jamshed 23076404edcSAsim Jamshed walk = TAILQ_FIRST(&ap->free_list); 23176404edcSAsim Jamshed while (walk) { 23276404edcSAsim Jamshed next = TAILQ_NEXT(walk, addr_link); 23376404edcSAsim Jamshed 23476404edcSAsim Jamshed if (saddr->sin_addr.s_addr != INADDR_ANY && 23576404edcSAsim Jamshed walk->addr.sin_addr.s_addr != saddr->sin_addr.s_addr) { 23676404edcSAsim Jamshed walk = next; 23776404edcSAsim Jamshed continue; 23876404edcSAsim Jamshed } 23976404edcSAsim Jamshed 24076404edcSAsim Jamshed if (saddr->sin_port != INPORT_ANY && 24176404edcSAsim Jamshed walk->addr.sin_port != saddr->sin_port) { 24276404edcSAsim Jamshed walk = next; 24376404edcSAsim Jamshed continue; 24476404edcSAsim Jamshed } 24576404edcSAsim Jamshed 24676404edcSAsim Jamshed rss_core = GetRSSCPUCore(ntohl(walk->addr.sin_addr.s_addr), 24776404edcSAsim Jamshed ntohl(daddr->sin_addr.s_addr), ntohs(walk->addr.sin_port), 248b88bd7d2SAsim Jamshed ntohs(daddr->sin_port), num_queues, endian_check); 24976404edcSAsim Jamshed 25076404edcSAsim Jamshed if (core == rss_core) 25176404edcSAsim Jamshed break; 25276404edcSAsim Jamshed 25376404edcSAsim Jamshed walk = next; 25476404edcSAsim Jamshed } 25576404edcSAsim Jamshed 25676404edcSAsim Jamshed if (walk) { 25776404edcSAsim Jamshed *saddr = walk->addr; 25876404edcSAsim Jamshed TAILQ_REMOVE(&ap->free_list, walk, addr_link); 25976404edcSAsim Jamshed TAILQ_INSERT_TAIL(&ap->used_list, walk, addr_link); 26076404edcSAsim Jamshed ap->num_free--; 26176404edcSAsim Jamshed ap->num_used++; 26276404edcSAsim Jamshed ret = 0; 26376404edcSAsim Jamshed } 26476404edcSAsim Jamshed 26576404edcSAsim Jamshed pthread_mutex_unlock(&ap->lock); 26676404edcSAsim Jamshed 26776404edcSAsim Jamshed return ret; 26876404edcSAsim Jamshed } 26976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 27076404edcSAsim Jamshed int 2712efd908dSAsim Jamshed FetchAddressPerCore(addr_pool_t ap, int core, int num_queues, 2722efd908dSAsim Jamshed const struct sockaddr_in *daddr, struct sockaddr_in *saddr) 2732efd908dSAsim Jamshed { 2742efd908dSAsim Jamshed struct addr_entry *walk; 2752efd908dSAsim Jamshed int ret = -1; 2762efd908dSAsim Jamshed 2772efd908dSAsim Jamshed if (!ap || !daddr || !saddr) 2782efd908dSAsim Jamshed return -1; 2792efd908dSAsim Jamshed 2802efd908dSAsim Jamshed pthread_mutex_lock(&ap->lock); 2812efd908dSAsim Jamshed 2822efd908dSAsim Jamshed /* we don't need to calculate RSSCPUCore if mtcp_init_rss is called */ 2832efd908dSAsim Jamshed walk = TAILQ_FIRST(&ap->free_list); 2842efd908dSAsim Jamshed if (walk) { 2852efd908dSAsim Jamshed *saddr = walk->addr; 2862efd908dSAsim Jamshed TAILQ_REMOVE(&ap->free_list, walk, addr_link); 2872efd908dSAsim Jamshed TAILQ_INSERT_TAIL(&ap->used_list, walk, addr_link); 2882efd908dSAsim Jamshed ap->num_free--; 2892efd908dSAsim Jamshed ap->num_used++; 2902efd908dSAsim Jamshed ret = 0; 2912efd908dSAsim Jamshed } 2922efd908dSAsim Jamshed 2932efd908dSAsim Jamshed pthread_mutex_unlock(&ap->lock); 2942efd908dSAsim Jamshed 2952efd908dSAsim Jamshed return ret; 2962efd908dSAsim Jamshed } 2972efd908dSAsim Jamshed /*----------------------------------------------------------------------------*/ 2982efd908dSAsim Jamshed int 29976404edcSAsim Jamshed FreeAddress(addr_pool_t ap, const struct sockaddr_in *addr) 30076404edcSAsim Jamshed { 30176404edcSAsim Jamshed struct addr_entry *walk, *next; 30276404edcSAsim Jamshed int ret = -1; 30376404edcSAsim Jamshed 30476404edcSAsim Jamshed if (!ap || !addr) 30576404edcSAsim Jamshed return -1; 30676404edcSAsim Jamshed 30776404edcSAsim Jamshed pthread_mutex_lock(&ap->lock); 30876404edcSAsim Jamshed 30976404edcSAsim Jamshed if (ap->mapper) { 31076404edcSAsim Jamshed uint32_t addr_h = ntohl(addr->sin_addr.s_addr); 31176404edcSAsim Jamshed uint16_t port_h = ntohs(addr->sin_port); 31276404edcSAsim Jamshed int index = addr_h - ap->addr_base; 31376404edcSAsim Jamshed 314*77f2f4e7SAsim Jamshed if (index >= 0 && index < ap->num_addr) { 31576404edcSAsim Jamshed walk = ap->mapper[addr_h - ap->addr_base].addrmap[port_h]; 31676404edcSAsim Jamshed } else { 31776404edcSAsim Jamshed walk = NULL; 31876404edcSAsim Jamshed } 31976404edcSAsim Jamshed 32076404edcSAsim Jamshed } else { 32176404edcSAsim Jamshed walk = TAILQ_FIRST(&ap->used_list); 32276404edcSAsim Jamshed while (walk) { 32376404edcSAsim Jamshed next = TAILQ_NEXT(walk, addr_link); 32476404edcSAsim Jamshed if (addr->sin_port == walk->addr.sin_port && 32576404edcSAsim Jamshed addr->sin_addr.s_addr == walk->addr.sin_addr.s_addr) { 32676404edcSAsim Jamshed break; 32776404edcSAsim Jamshed } 32876404edcSAsim Jamshed 32976404edcSAsim Jamshed walk = next; 33076404edcSAsim Jamshed } 33176404edcSAsim Jamshed 33276404edcSAsim Jamshed } 33376404edcSAsim Jamshed 33476404edcSAsim Jamshed if (walk) { 33576404edcSAsim Jamshed TAILQ_REMOVE(&ap->used_list, walk, addr_link); 33676404edcSAsim Jamshed TAILQ_INSERT_TAIL(&ap->free_list, walk, addr_link); 33776404edcSAsim Jamshed ap->num_free++; 33876404edcSAsim Jamshed ap->num_used--; 33976404edcSAsim Jamshed ret = 0; 34076404edcSAsim Jamshed } 34176404edcSAsim Jamshed 34276404edcSAsim Jamshed pthread_mutex_unlock(&ap->lock); 34376404edcSAsim Jamshed 34476404edcSAsim Jamshed return ret; 34576404edcSAsim Jamshed } 34676404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 347