xref: /mOS-networking-stack/core/src/addr_pool.c (revision d270d183)
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;
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
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
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
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
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