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
CreateAddressPool(in_addr_t addr_base,int num_addr)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
CreateAddressPoolPerCore(int core,int num_queues,in_addr_t saddr_base,int num_addr,in_addr_t daddr,in_port_t dport)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;
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 pthread_mutex_lock(&ap->lock);
150
151 ap->addr_base = ntohl(saddr_base);
152 ap->num_addr = num_addr;
153 daddr_h = ntohl(daddr);
154 dport_h = ntohs(dport);
155
156 /* search address space to get RSS-friendly addresses */
157 cnt = 0;
158 for (i = 0; i < num_addr; i++) {
159 saddr_h = ap->addr_base + i;
160 saddr = htonl(saddr_h);
161 for (j = MIN_PORT; j < MAX_PORT; j++) {
162 if (cnt >= num_entry)
163 break;
164
165 sport_h = j;
166 rss_core = GetRSSCPUCore(daddr_h, saddr_h, dport_h, sport_h,
167 num_queues);
168 if (rss_core != core)
169 continue;
170
171 ap->pool[cnt].addr.sin_addr.s_addr = saddr;
172 ap->pool[cnt].addr.sin_port = htons(sport_h);
173 ap->mapper[i].addrmap[j] = &ap->pool[cnt];
174 TAILQ_INSERT_TAIL(&ap->free_list, &ap->pool[cnt], addr_link);
175 cnt++;
176 }
177 }
178
179 ap->num_entry = cnt;
180 ap->num_free = cnt;
181 ap->num_used = 0;
182 //fprintf(stderr, "CPU %d: Created %d address entries.\n", core, cnt);
183 if (ap->num_entry < g_config.mos->max_concurrency) {
184 fprintf(stderr, "[WARINING] Available # addresses (%d) is smaller than"
185 " the max concurrency (%d).\n",
186 ap->num_entry, g_config.mos->max_concurrency);
187 }
188
189 pthread_mutex_unlock(&ap->lock);
190
191 return ap;
192 }
193 /*----------------------------------------------------------------------------*/
194 void
DestroyAddressPool(addr_pool_t ap)195 DestroyAddressPool(addr_pool_t ap)
196 {
197 if (!ap)
198 return;
199
200 if (ap->pool) {
201 free(ap->pool);
202 ap->pool = NULL;
203 }
204
205 if (ap->mapper) {
206 free(ap->mapper);
207 ap->mapper = NULL;
208 }
209
210 pthread_mutex_destroy(&ap->lock);
211
212 free(ap);
213 }
214 /*----------------------------------------------------------------------------*/
215 int
FetchAddress(addr_pool_t ap,int core,int num_queues,const struct sockaddr_in * daddr,struct sockaddr_in * saddr)216 FetchAddress(addr_pool_t ap, int core, int num_queues,
217 const struct sockaddr_in *daddr, struct sockaddr_in *saddr)
218 {
219 struct addr_entry *walk, *next;
220 int rss_core;
221 int ret = -1;
222
223 if (!ap || !daddr || !saddr)
224 return -1;
225
226 pthread_mutex_lock(&ap->lock);
227
228 walk = TAILQ_FIRST(&ap->free_list);
229 while (walk) {
230 next = TAILQ_NEXT(walk, addr_link);
231
232 if (saddr->sin_addr.s_addr != INADDR_ANY &&
233 walk->addr.sin_addr.s_addr != saddr->sin_addr.s_addr) {
234 walk = next;
235 continue;
236 }
237
238 if (saddr->sin_port != INPORT_ANY &&
239 walk->addr.sin_port != saddr->sin_port) {
240 walk = next;
241 continue;
242 }
243
244 rss_core = GetRSSCPUCore(ntohl(walk->addr.sin_addr.s_addr),
245 ntohl(daddr->sin_addr.s_addr), ntohs(walk->addr.sin_port),
246 ntohs(daddr->sin_port), num_queues);
247
248 if (core == rss_core)
249 break;
250
251 walk = next;
252 }
253
254 if (walk) {
255 *saddr = walk->addr;
256 TAILQ_REMOVE(&ap->free_list, walk, addr_link);
257 TAILQ_INSERT_TAIL(&ap->used_list, walk, addr_link);
258 ap->num_free--;
259 ap->num_used++;
260 ret = 0;
261 }
262
263 pthread_mutex_unlock(&ap->lock);
264
265 return ret;
266 }
267 /*----------------------------------------------------------------------------*/
268 int
FetchAddressPerCore(addr_pool_t ap,int core,int num_queues,const struct sockaddr_in * daddr,struct sockaddr_in * saddr)269 FetchAddressPerCore(addr_pool_t ap, int core, int num_queues,
270 const struct sockaddr_in *daddr, struct sockaddr_in *saddr)
271 {
272 struct addr_entry *walk;
273 int ret = -1;
274
275 if (!ap || !daddr || !saddr)
276 return -1;
277
278 pthread_mutex_lock(&ap->lock);
279
280 /* we don't need to calculate RSSCPUCore if mtcp_init_rss is called */
281 walk = TAILQ_FIRST(&ap->free_list);
282 if (walk) {
283 *saddr = walk->addr;
284 TAILQ_REMOVE(&ap->free_list, walk, addr_link);
285 TAILQ_INSERT_TAIL(&ap->used_list, walk, addr_link);
286 ap->num_free--;
287 ap->num_used++;
288 ret = 0;
289 }
290
291 pthread_mutex_unlock(&ap->lock);
292
293 return ret;
294 }
295 /*----------------------------------------------------------------------------*/
296 int
FreeAddress(addr_pool_t ap,const struct sockaddr_in * addr)297 FreeAddress(addr_pool_t ap, const struct sockaddr_in *addr)
298 {
299 struct addr_entry *walk, *next;
300 int ret = -1;
301
302 if (!ap || !addr)
303 return -1;
304
305 pthread_mutex_lock(&ap->lock);
306
307 if (ap->mapper) {
308 uint32_t addr_h = ntohl(addr->sin_addr.s_addr);
309 uint16_t port_h = ntohs(addr->sin_port);
310 int index = addr_h - ap->addr_base;
311
312 if (index >= 0 && index < ap->num_addr) {
313 walk = ap->mapper[addr_h - ap->addr_base].addrmap[port_h];
314 } else {
315 walk = NULL;
316 }
317
318 } else {
319 walk = TAILQ_FIRST(&ap->used_list);
320 while (walk) {
321 next = TAILQ_NEXT(walk, addr_link);
322 if (addr->sin_port == walk->addr.sin_port &&
323 addr->sin_addr.s_addr == walk->addr.sin_addr.s_addr) {
324 break;
325 }
326
327 walk = next;
328 }
329
330 }
331
332 if (walk) {
333 TAILQ_REMOVE(&ap->used_list, walk, addr_link);
334 TAILQ_INSERT_TAIL(&ap->free_list, walk, addr_link);
335 ap->num_free++;
336 ap->num_used--;
337 ret = 0;
338 }
339
340 pthread_mutex_unlock(&ap->lock);
341
342 return ret;
343 }
344 /*----------------------------------------------------------------------------*/
345