aboutsummaryrefslogtreecommitdiff
path: root/src/ats
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-10-17 09:40:36 +0000
committerChristian Grothoff <christian@grothoff.org>2011-10-17 09:40:36 +0000
commitba8c01f2e3d41fb21dd8efa3dcfe2cc555d5f530 (patch)
treef340ced5207da20651c1b7daa729f69f64523bc2 /src/ats
parent710709c0d4eaa001fa185b5b72972666cb64f926 (diff)
downloadgnunet-ba8c01f2e3d41fb21dd8efa3dcfe2cc555d5f530.tar.gz
gnunet-ba8c01f2e3d41fb21dd8efa3dcfe2cc555d5f530.zip
towards nicer scheduling code
Diffstat (limited to 'src/ats')
-rw-r--r--src/ats/gnunet-service-ats_addresses.c298
1 files changed, 230 insertions, 68 deletions
diff --git a/src/ats/gnunet-service-ats_addresses.c b/src/ats/gnunet-service-ats_addresses.c
index 68d4b03de..f8cd2ab16 100644
--- a/src/ats/gnunet-service-ats_addresses.c
+++ b/src/ats/gnunet-service-ats_addresses.c
@@ -25,6 +25,7 @@
25 * @author Christian Grothoff 25 * @author Christian Grothoff
26 */ 26 */
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_ats_service.h"
28#include "gnunet-service-ats_addresses.h" 29#include "gnunet-service-ats_addresses.h"
29#include "gnunet-service-ats_performance.h" 30#include "gnunet-service-ats_performance.h"
30#include "gnunet-service-ats_scheduling.h" 31#include "gnunet-service-ats_scheduling.h"
@@ -46,12 +47,12 @@ struct ATS_Address
46 47
47 struct GNUNET_ATS_Information * ats; 48 struct GNUNET_ATS_Information * ats;
48 49
50 struct GNUNET_TIME_Relative atsp_latency;
51
49 struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_in; 52 struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_in;
50 53
51 struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_out; 54 struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_out;
52 55
53 struct GNUNET_TIME_Relative atsp_latency;
54
55 uint32_t atsp_distance; 56 uint32_t atsp_distance;
56 57
57 uint32_t atsp_cost_wan; 58 uint32_t atsp_cost_wan;
@@ -64,9 +65,10 @@ struct ATS_Address
64 65
65 struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_out; 66 struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_out;
66 67
67 struct GNUNET_BANDWIDTH_Value32NBO bw_in; 68 /**
68 69 * Is this the active address for this peer?
69 struct GNUNET_BANDWIDTH_Value32NBO bw_out; 70 */
71 int active;
70 72
71}; 73};
72 74
@@ -80,75 +82,138 @@ static unsigned long long total_quota_out;
80static unsigned int active_addr_count; 82static unsigned int active_addr_count;
81 83
82 84
83struct CompareAddressContext 85/**
86 * Update a bandwidth assignment for a peer. This trivial method currently
87 * simply assigns the same share to all active connections.
88 *
89 * @param cls unused
90 * @param key unused
91 * @param value the 'struct ATS_Address'
92 * @return GNUNET_OK (continue to iterate)
93 */
94static int
95update_bw_it (void *cls,
96 const GNUNET_HashCode * key,
97 void *value)
84{ 98{
85 struct ATS_Address * search; 99 struct ATS_Address *aa = value;
86 struct ATS_Address * result; 100
87}; 101 if (GNUNET_YES != aa->active)
102 return GNUNET_OK;
103 aa->assigned_bw_in.value__ = htonl (total_quota_in / active_addr_count);
104 aa->assigned_bw_out.value__ = htonl (total_quota_out / active_addr_count);
105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
106 "New bandwidth for peer %s is %u/%u\n",
107 GNUNET_i2s (&aa->peer),
108 ntohl (aa->assigned_bw_in.value__),
109 ntohl (aa->assigned_bw_out.value__));
110 GAS_scheduling_transmit_address_suggestion (&aa->peer,
111 aa->plugin,
112 aa->addr, aa->addr_len,
113 aa->session_id,
114 aa->ats, aa->ats_count,
115 aa->assigned_bw_out, aa->assigned_bw_in);
116 GAS_reservations_set_bandwidth (&aa->peer,
117 aa->assigned_bw_in);
118 GAS_performance_notify_clients (&aa->peer,
119 aa->plugin,
120 aa->addr, aa->addr_len,
121 aa->ats, aa->ats_count,
122 aa->assigned_bw_out, aa->assigned_bw_in);
123 return GNUNET_OK;
124}
88 125
89 126
127/**
128 * Some (significant) input changed, recalculate bandwidth assignment
129 * for all peers.
130 */
90static void 131static void
132recalculate_assigned_bw ()
133{
134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
135 "Recalculating bandwidth for all active connections\n");
136 GNUNET_CONTAINER_multihashmap_iterate (addresses,
137 &update_bw_it,
138 NULL);
139}
140
141
142/**
143 * Destroy the given address.
144 *
145 * @param addr address to destroy
146 * @return GNUNET_YES if bandwidth allocations should be recalcualted
147 */
148static int
91destroy_address (struct ATS_Address *addr) 149destroy_address (struct ATS_Address *addr)
92{ 150{
151 int ret;
152
153 ret = GNUNET_NO;
93 GNUNET_assert (GNUNET_YES == 154 GNUNET_assert (GNUNET_YES ==
94 GNUNET_CONTAINER_multihashmap_remove(addresses, 155 GNUNET_CONTAINER_multihashmap_remove(addresses,
95 &addr->peer.hashPubKey, 156 &addr->peer.hashPubKey,
96 addr)); 157 addr));
97 if (ntohl (addr->bw_in.value__) > 0) 158 if (GNUNET_YES == addr->active)
98 { 159 {
99 active_addr_count--; 160 active_addr_count--;
100 // FIXME: update address assignment for other peers... 161 ret = GNUNET_YES;
101 } 162 }
102 GNUNET_free_non_null (addr->ats); 163 GNUNET_free_non_null (addr->ats);
103 GNUNET_free (addr->plugin); 164 GNUNET_free (addr->plugin);
104 GNUNET_free (addr); 165 GNUNET_free (addr);
166 return ret;
105} 167}
106 168
107 169
170struct CompareAddressContext
171{
172 const struct ATS_Address * search;
173 struct ATS_Address * result;
174};
175
176
108static int 177static int
109compare_address_it (void *cls, 178compare_address_it (void *cls,
110 const GNUNET_HashCode * key, 179 const GNUNET_HashCode * key,
111 void *value) 180 void *value)
112{ 181{
113 struct CompareAddressContext * cac = cls; 182 struct CompareAddressContext * cac = cls;
114 struct ATS_Address * aa = (struct ATS_Address *) value; 183 struct ATS_Address * aa = value;
115
116 /* compare sessions */
117 if (aa->session_id != cac->search->session_id)
118 return GNUNET_YES;
119
120 if (aa->addr_len != cac->search->addr_len)
121 {
122 return GNUNET_YES;
123 }
124 184
125 if (0 == strcmp(aa->plugin, cac->search->plugin)) 185 if ( ( (aa->addr_len != cac->search->addr_len) ||
126 { 186 (0 != strcmp(aa->plugin, cac->search->plugin)) ||
187 (0 != memcmp (aa->addr, cac->search->addr, aa->addr_len)) ) &&
188 ( (aa->session_id != cac->search->session_id) ||
189 (cac->search->session_id == 0) ))
127 return GNUNET_YES; 190 return GNUNET_YES;
128 } 191 cac->result = aa;
129 192 return GNUNET_NO;
130 if (0 == memcmp (aa->addr, cac->search->addr, aa->addr_len))
131 {
132 cac->result = aa;
133 return GNUNET_NO;
134 }
135 return GNUNET_YES;
136} 193}
137 194
138 195
196/**
197 * Find an existing equivalent address record.
198 * Compares by peer identity and network address OR by session ID
199 * (one of the two must match).
200 *
201 * @param peer peer to lookup addresses for
202 * @param addr existing address record
203 * @return existing address record, NULL for none
204 */
139struct ATS_Address * 205struct ATS_Address *
140find_address (const struct GNUNET_PeerIdentity *peer, 206find_address (const struct GNUNET_PeerIdentity *peer,
141 struct ATS_Address * addr) 207 const struct ATS_Address * addr)
142{ 208{
143 struct CompareAddressContext cac; 209 struct CompareAddressContext cac;
210
144 cac.result = NULL; 211 cac.result = NULL;
145 cac.search = addr; 212 cac.search = addr;
146
147 GNUNET_CONTAINER_multihashmap_get_multiple(addresses, 213 GNUNET_CONTAINER_multihashmap_get_multiple(addresses,
148 &peer->hashPubKey, 214 &peer->hashPubKey,
149 compare_address_it, 215 compare_address_it,
150 &cac); 216 &cac);
151
152 return cac.result; 217 return cac.result;
153} 218}
154 219
@@ -163,6 +228,7 @@ GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
163{ 228{
164 struct ATS_Address * aa; 229 struct ATS_Address * aa;
165 struct ATS_Address * old; 230 struct ATS_Address * old;
231 uint32_t i;
166 232
167 aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len); 233 aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
168 aa->ats = GNUNET_malloc(atsi_count * sizeof (struct GNUNET_ATS_Information)); 234 aa->ats = GNUNET_malloc(atsi_count * sizeof (struct GNUNET_ATS_Information));
@@ -185,18 +251,50 @@ GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
186 "Added new address for peer `%s' %X\n", 252 "Added new address for peer `%s' %X\n",
187 GNUNET_i2s (peer), aa); 253 GNUNET_i2s (peer), aa);
188 return; 254 old = aa;
189 } 255 }
190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 256 else
191 "Updated existing address for peer `%s' %X \n", 257 {
192 GNUNET_i2s (peer), old); 258 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
193 GNUNET_free_non_null (old->ats); 259 "Updated existing address for peer `%s' %X \n",
194 old->ats = NULL; 260 GNUNET_i2s (peer), old);
195 old->ats_count = 0; 261 GNUNET_free_non_null (old->ats);
196 old->ats = aa->ats; 262 old->session_id = session_id;
197 old->ats_count = aa->ats_count; 263 old->ats = NULL;
198 GNUNET_free (aa->plugin); 264 old->ats_count = 0;
199 GNUNET_free (aa); 265 old->ats = aa->ats;
266 old->ats_count = aa->ats_count;
267 GNUNET_free (aa->plugin);
268 GNUNET_free (aa);
269 }
270 for (i=0;i<atsi_count;i++)
271 switch (atsi[i].type)
272 {
273 case GNUNET_ATS_UTILIZATION_UP:
274 old->atsp_utilization_out.value__ = atsi[i].value;
275 break;
276 case GNUNET_ATS_UTILIZATION_DOWN:
277 old->atsp_utilization_in.value__ = atsi[i].value;
278 break;
279 case GNUNET_ATS_QUALITY_NET_DELAY:
280 old->atsp_latency.rel_value = ntohl (atsi[i].value);
281 break;
282 case GNUNET_ATS_QUALITY_NET_DISTANCE:
283 old->atsp_distance = ntohl (atsi[i].value);
284 break;
285 case GNUNET_ATS_COST_WAN:
286 old->atsp_cost_wan = ntohl (atsi[i].value);
287 break;
288 case GNUNET_ATS_COST_LAN:
289 old->atsp_cost_lan = ntohl (atsi[i].value);
290 break;
291 case GNUNET_ATS_COST_WLAN:
292 old->atsp_cost_wlan = ntohl (atsi[i].value);
293 break;
294 default:
295 GNUNET_break (0);
296 break;
297 }
200} 298}
201 299
202 300
@@ -206,7 +304,6 @@ GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
206 const void *plugin_addr, size_t plugin_addr_len, 304 const void *plugin_addr, size_t plugin_addr_len,
207 uint32_t session_id) 305 uint32_t session_id)
208{ 306{
209
210 struct ATS_Address aa; 307 struct ATS_Address aa;
211 struct ATS_Address *res; 308 struct ATS_Address *res;
212 309
@@ -215,7 +312,6 @@ GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
215 aa.addr = plugin_addr; 312 aa.addr = plugin_addr;
216 aa.plugin = (char*) plugin_name; 313 aa.plugin = (char*) plugin_name;
217 aa.session_id = session_id; 314 aa.session_id = session_id;
218
219 res = find_address (peer, &aa); 315 res = find_address (peer, &aa);
220 if (res == NULL) 316 if (res == NULL)
221 { 317 {
@@ -225,10 +321,75 @@ GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
225 GNUNET_i2s (peer)); 321 GNUNET_i2s (peer));
226 return; 322 return;
227 } 323 }
324 if ( (aa.session_id == session_id) &&
325 (session_id != 0) &&
326 (res->addr_len > 0) )
327 {
328 /* just session died */
329 res->session_id = 0;
330 if (GNUNET_YES == addr->active)
331 {
332 active_addr_count--;
333 ret = GNUNET_YES;
334 recalculate_assigned_bw ();
335 }
336 return;
337 }
338 /* destroy address entirely (either was only session or was
339 not even with a session) */
228 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
229 "Deleting address for peer `%s': `%s'\n", 341 "Deleting address for peer `%s': `%s'\n",
230 GNUNET_i2s (peer), plugin_name); 342 GNUNET_i2s (peer), plugin_name);
231 destroy_address (res); 343 if (GNUNET_YES == destroy_address (res))
344 recalculate_assigned_bw ();
345}
346
347
348/**
349 * Find a "good" address to use for a peer. If we already have an existing
350 * address, we stick to it. Otherwise, we pick by lowest distance and then
351 * by lowest latency.
352 *
353 * @param cls the 'struct ATS_Address**' where we store the result
354 * @param key unused
355 * @param value another 'struct ATS_Address*' to consider using
356 * @return GNUNET_OK (continue to iterate)
357 */
358static int
359find_address_it (void *cls,
360 const GNUNET_HashCode * key,
361 void *value)
362{
363 struct ATS_Address **ap = cls;
364 struct ATS_Address * aa = (struct ATS_Address *) value;
365 struct ATS_Address * ab = *ap;
366
367 if (NULL == ab)
368 {
369 *ap = aa;
370 return GNUNET_OK;
371 }
372 if ( (ntohl (ab->assigned_bw_in.value__) == 0) &&
373 (ntohl (aa->assigned_bw_in.value__) > 0) )
374 {
375 /* stick to existing connection */
376 *ap = aa;
377 return GNUNET_OK;
378 }
379 if (ab->atsp_distance > aa->atsp_distance)
380 {
381 /* user shorter distance */
382 *ap = aa;
383 return GNUNET_OK;
384 }
385 if (ab->atsp_latency.rel_value > aa->atsp_latency.rel_value)
386 {
387 /* user lower latency */
388 *ap = aa;
389 return GNUNET_OK;
390 }
391 /* don't care */
392 return GNUNET_OK;
232} 393}
233 394
234 395
@@ -237,7 +398,11 @@ GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer)
237{ 398{
238 struct ATS_Address * aa; 399 struct ATS_Address * aa;
239 400
240 aa = GNUNET_CONTAINER_multihashmap_get (addresses, &peer->hashPubKey); 401 aa = NULL;
402 GNUNET_CONTAINER_multihashmap_get_multiple (addresses,
403 &peer->hashPubKey,
404 &find_address_it,
405 &aa);
241 if (aa == NULL) 406 if (aa == NULL)
242 { 407 {
243 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -245,25 +410,21 @@ GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer)
245 GNUNET_i2s (peer)); 410 GNUNET_i2s (peer));
246 return; 411 return;
247 } 412 }
248 /* FIXME: ensure that we don't do this multiple times per peer! */ 413 if (aa->active == GNUNET_NO)
249 if (ntohl (aa->bw_in.value__) == 0)
250 { 414 {
415 aa->active = GNUNET_YES;
251 active_addr_count++; 416 active_addr_count++;
252 aa->bw_in.value__ = htonl (total_quota_in / active_addr_count); 417 recalculate_assigned_bw ();
253 aa->bw_out.value__ = htonl (total_quota_out / active_addr_count); 418 }
254 /* FIXME: update bw assignments for other addresses... */ 419 else
420 {
421 /* just to be sure... */
422 GAS_scheduling_transmit_address_suggestion (peer, aa->plugin,
423 aa->addr, aa->addr_len,
424 aa->session_id,
425 aa->ats, aa->ats_count,
426 aa->assigned_bw_out, aa->assigned_bw_in);
255 } 427 }
256 GAS_reservations_set_bandwidth (peer,
257 aa->bw_in);
258 GAS_scheduling_transmit_address_suggestion (peer, aa->plugin,
259 aa->addr, aa->addr_len,
260 aa->session_id,
261 aa->ats, aa->ats_count,
262 aa->bw_out, aa->bw_in);
263 GAS_performance_notify_clients (peer, aa->plugin,
264 aa->addr, aa->addr_len,
265 aa->ats, aa->ats_count,
266 aa->bw_out, aa->bw_in);
267} 428}
268 429
269 430
@@ -326,6 +487,7 @@ GAS_addresses_destroy_all ()
326 if (addresses != NULL) 487 if (addresses != NULL)
327 GNUNET_CONTAINER_multihashmap_iterate(addresses, 488 GNUNET_CONTAINER_multihashmap_iterate(addresses,
328 &free_address_it, NULL); 489 &free_address_it, NULL);
490 GNUNET_assert (active_addr_count == 0);
329} 491}
330 492
331 493