aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-10-06 21:03:33 +0200
committerChristian Grothoff <christian@grothoff.org>2019-10-06 21:03:33 +0200
commit622fd12c7101c53c1fa0f9563a831f3196732dc5 (patch)
treed86047807232d9921341b8ed84558dea2b9df929 /src
parent6c38429f96ff9128ebd983a85aa6a2024112ed25 (diff)
downloadgnunet-622fd12c7101c53c1fa0f9563a831f3196732dc5.tar.gz
gnunet-622fd12c7101c53c1fa0f9563a831f3196732dc5.zip
remove dead, obsolete or never-to-become ATS logic (DCE)
Diffstat (limited to 'src')
-rw-r--r--src/ats-tests/Makefile.am116
-rw-r--r--src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_mlp.conf24
-rw-r--r--src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_mlp.exp46
-rw-r--r--src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_ril.conf24
-rw-r--r--src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_ril.exp46
-rw-r--r--src/ats-tests/perf_ats_mlp_bandwidth.conf4
-rw-r--r--src/ats-tests/perf_ats_mlp_latency.conf4
-rw-r--r--src/ats-tests/perf_ats_mlp_none.conf4
-rw-r--r--src/ats-tests/perf_ats_ril_bandwidth.conf4
-rw-r--r--src/ats-tests/perf_ats_ril_latency.conf4
-rw-r--r--src/ats-tests/perf_ats_ril_none.conf4
-rw-r--r--src/ats/Makefile.am127
-rw-r--r--src/ats/ats2.h294
-rw-r--r--src/ats/ats_api2_application.c366
-rw-r--r--src/ats/ats_api2_transport.c689
-rw-r--r--src/ats/gnunet-service-ats-new.c804
-rw-r--r--src/ats/perf_ats_solver_mlp.conf0
-rw-r--r--src/ats/perf_ats_solver_ril.conf0
-rw-r--r--src/ats/plugin_ats2_common.c99
-rw-r--r--src/ats/plugin_ats2_simple.c1087
-rw-r--r--src/ats/plugin_ats_mlp.c2924
-rw-r--r--src/ats/plugin_ats_ril.c2997
-rw-r--r--src/ats/test_ats2_lib.c259
-rw-r--r--src/ats/test_ats2_lib.conf13
-rw-r--r--src/ats/test_ats2_lib.h523
-rw-r--r--src/ats/test_ats_api_mlp.conf45
-rw-r--r--src/ats/test_ats_api_ril.conf24
-rw-r--r--src/ats/test_ats_solver_delayed_mlp.conf20
-rw-r--r--src/ats/test_ats_solver_delayed_ril.conf31
-rw-r--r--src/include/Makefile.am1
-rw-r--r--src/include/gnunet_ats_plugin_new.h247
31 files changed, 8 insertions, 10822 deletions
diff --git a/src/ats-tests/Makefile.am b/src/ats-tests/Makefile.am
index 1804a43bf..c965fcc9f 100644
--- a/src/ats-tests/Makefile.am
+++ b/src/ats-tests/Makefile.am
@@ -9,18 +9,6 @@ if USE_COVERAGE
9 AM_CFLAGS = -fprofile-arcs -ftest-coverage 9 AM_CFLAGS = -fprofile-arcs -ftest-coverage
10endif 10endif
11 11
12if HAVE_EXPERIMENTAL
13if HAVE_LIBGLPK
14 PERF_MLP = \
15 perf_ats_mlp_transport_none \
16 perf_ats_mlp_transport_bandwidth \
17 perf_ats_mlp_transport_latency \
18 perf_ats_mlp_core_none \
19 perf_ats_mlp_core_bandwidth \
20 perf_ats_mlp_core_latency
21endif
22endif
23
24if HAVE_TESTING 12if HAVE_TESTING
25TESTING_TESTS = \ 13TESTING_TESTS = \
26 perf_ats_proportional_transport_none \ 14 perf_ats_proportional_transport_none \
@@ -31,8 +19,6 @@ TESTING_TESTS = \
31 perf_ats_proportional_core_latency \ 19 perf_ats_proportional_core_latency \
32 $(PERF_MLP) 20 $(PERF_MLP)
33 21
34# RIL-tests commented out as RIL is currently badly broken.
35# perf_ats_ril_transport_none perf_ats_ril_core_none perf_ats_ril_transport_bandwidth perf_ats_ril_core_bandwidth perf_ats_ril_transport_latency perf_ats_ril_core_latency
36endif 22endif
37 23
38lib_LTLIBRARIES = \ 24lib_LTLIBRARIES = \
@@ -56,7 +42,7 @@ libgnunetatstesting_la_SOURCES = \
56libgnunetatstesting_la_LIBADD = \ 42libgnunetatstesting_la_LIBADD = \
57 $(top_builddir)/src/testbed/libgnunettestbed.la \ 43 $(top_builddir)/src/testbed/libgnunettestbed.la \
58 $(top_builddir)/src/core/libgnunetcore.la \ 44 $(top_builddir)/src/core/libgnunetcore.la \
59 $(top_builddir)/src/transport/libgnunettransport.la \ 45 $(top_builddir)/src/transport/libgnunettransport.la \
60 $(top_builddir)/src/ats/libgnunetats.la \ 46 $(top_builddir)/src/ats/libgnunetats.la \
61 $(top_builddir)/src/util/libgnunetutil.la \ 47 $(top_builddir)/src/util/libgnunetutil.la \
62 $(GN_LIBINTL) 48 $(GN_LIBINTL)
@@ -168,106 +154,8 @@ perf_ats_proportional_transport_latency_DEPENDENCIES = \
168 libgnunetatstesting.la \ 154 libgnunetatstesting.la \
169 $(top_builddir)/src/util/libgnunetutil.la 155 $(top_builddir)/src/util/libgnunetutil.la
170 156
171perf_ats_mlp_core_none_SOURCES = \
172 perf_ats.c
173perf_ats_mlp_core_none_LDADD = \
174 $(top_builddir)/src/util/libgnunetutil.la \
175 $(top_builddir)/src/ats-tests/libgnunetatstesting.la \
176 $(top_builddir)/src/testbed/libgnunettestbed.la \
177 $(top_builddir)/src/ats/libgnunetats.la \
178 $(top_builddir)/src/core/libgnunetcore.la \
179 $(top_builddir)/src/transport/libgnunettransport.la
180perf_ats_mlp_core_none_DEPENDENCIES = \
181 libgnunetatstesting.la \
182 $(top_builddir)/src/util/libgnunetutil.la
183
184perf_ats_mlp_transport_none_SOURCES = \
185 perf_ats.c
186perf_ats_mlp_transport_none_LDADD = \
187 $(top_builddir)/src/util/libgnunetutil.la \
188 $(top_builddir)/src/ats-tests/libgnunetatstesting.la \
189 $(top_builddir)/src/testbed/libgnunettestbed.la \
190 $(top_builddir)/src/ats/libgnunetats.la \
191 $(top_builddir)/src/core/libgnunetcore.la \
192 $(top_builddir)/src/transport/libgnunettransport.la
193perf_ats_mlp_transport_none_DEPENDENCIES = \
194 libgnunetatstesting.la \
195 $(top_builddir)/src/util/libgnunetutil.la
196
197perf_ats_mlp_core_bandwidth_SOURCES = \
198 perf_ats.c
199perf_ats_mlp_core_bandwidth_LDADD = \
200 $(top_builddir)/src/util/libgnunetutil.la \
201 $(top_builddir)/src/ats-tests/libgnunetatstesting.la \
202 $(top_builddir)/src/testbed/libgnunettestbed.la \
203 $(top_builddir)/src/ats/libgnunetats.la \
204 $(top_builddir)/src/core/libgnunetcore.la \
205 $(top_builddir)/src/transport/libgnunettransport.la
206perf_ats_mlp_core_bandwidth_DEPENDENCIES = \
207 libgnunetatstesting.la \
208 $(top_builddir)/src/util/libgnunetutil.la
209
210perf_ats_mlp_transport_bandwidth_SOURCES = \
211 perf_ats.c
212perf_ats_mlp_transport_bandwidth_LDADD = \
213 $(top_builddir)/src/util/libgnunetutil.la \
214 $(top_builddir)/src/ats-tests/libgnunetatstesting.la \
215 $(top_builddir)/src/testbed/libgnunettestbed.la \
216 $(top_builddir)/src/ats/libgnunetats.la \
217 $(top_builddir)/src/core/libgnunetcore.la \
218 $(top_builddir)/src/transport/libgnunettransport.la
219perf_ats_mlp_transport_bandwidth_DEPENDENCIES = \
220 libgnunetatstesting.la \
221 $(top_builddir)/src/util/libgnunetutil.la
222
223perf_ats_mlp_core_latency_SOURCES = \
224 perf_ats.c
225perf_ats_mlp_core_latency_LDADD = \
226 $(top_builddir)/src/util/libgnunetutil.la \
227 $(top_builddir)/src/ats-tests/libgnunetatstesting.la \
228 $(top_builddir)/src/testbed/libgnunettestbed.la \
229 $(top_builddir)/src/ats/libgnunetats.la \
230 $(top_builddir)/src/core/libgnunetcore.la \
231 $(top_builddir)/src/transport/libgnunettransport.la
232perf_ats_mlp_core_latency_DEPENDENCIES = \
233 libgnunetatstesting.la \
234 $(top_builddir)/src/util/libgnunetutil.la
235
236perf_ats_mlp_transport_latency_SOURCES = \
237 perf_ats.c
238perf_ats_mlp_transport_latency_LDADD = \
239 $(top_builddir)/src/util/libgnunetutil.la \
240 $(top_builddir)/src/ats-tests/libgnunetatstesting.la \
241 $(top_builddir)/src/testbed/libgnunettestbed.la \
242 $(top_builddir)/src/ats/libgnunetats.la \
243 $(top_builddir)/src/core/libgnunetcore.la \
244 $(top_builddir)/src/transport/libgnunettransport.la
245perf_ats_mlp_transport_latencyDEPENDENCIES = \
246 $(top_builddir)/src/ats-tests/libgnunetatstesting.la \
247 $(top_builddir)/src/util/libgnunetutil.la
248
249#perf_ats_ril_core_none_SOURCES = \
250# perf_ats.c
251#perf_ats_ril_core_none_LDADD = \
252# $(top_builddir)/src/util/libgnunetutil.la \
253# $(top_builddir)/src/ats-tests/libgnunetatstesting.la \
254# $(top_builddir)/src/testbed/libgnunettestbed.la \
255# $(top_builddir)/src/ats/libgnunetats.la \
256# $(top_builddir)/src/core/libgnunetcore.la \
257# $(top_builddir)/src/transport/libgnunettransport.la
258#perf_ats_ril_core_none_DEPENDENCIES = \
259# libgnunetatstesting.la \
260# $(top_builddir)/src/util/libgnunetutil.la
261
262
263EXTRA_DIST = \ 157EXTRA_DIST = \
264 gnunet_ats_sim_default.conf \ 158 gnunet_ats_sim_default.conf \
265 perf_ats_proportional_none.conf \ 159 perf_ats_proportional_none.conf \
266 perf_ats_proportional_bandwidth.conf \ 160 perf_ats_proportional_bandwidth.conf \
267 perf_ats_proportional_latency.conf \ 161 perf_ats_proportional_latency.conf
268 perf_ats_mlp_none.conf \
269 perf_ats_mlp_bandwidth.conf \
270 perf_ats_mlp_latency.conf \
271 perf_ats_ril_none.conf \
272 perf_ats_ril_bandwidth.conf \
273 perf_ats_ril_latency.conf
diff --git a/src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_mlp.conf b/src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_mlp.conf
deleted file mode 100644
index 91697eda9..000000000
--- a/src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_mlp.conf
+++ /dev/null
@@ -1,24 +0,0 @@
1@INLINE@ template_perf_ats.conf
2
3[transport]
4plugins = unix
5
6[ats]
7MODE = PROPORTIONAL
8UNSPECIFIED_QUOTA_IN = 128 KiB
9UNSPECIFIED_QUOTA_OUT = 128 KiB
10# LOOPBACK
11LOOPBACK_QUOTA_IN = 128 KiB
12LOOPBACK_QUOTA_OUT = 128 KiB
13# LAN
14LAN_QUOTA_IN = 128 KiB
15LAN_QUOTA_OUT = 128 KiB
16# WAN
17WAN_QUOTA_IN = 128 KiB
18WAN_QUOTA_OUT = 128 KiB
19# WLAN
20WLAN_QUOTA_IN = 128 KiB
21WLAN_QUOTA_OUT = 128 KiB
22# BLUETOOTH
23BLUETOOTH_QUOTA_IN = 128 KiB
24BLUETOOTH_QUOTA_OUT = 128 KiB \ No newline at end of file
diff --git a/src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_mlp.exp b/src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_mlp.exp
deleted file mode 100644
index 9b4c998c4..000000000
--- a/src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_mlp.exp
+++ /dev/null
@@ -1,46 +0,0 @@
1[experiment]
2name = sc1_eval_dru_mlp
3masters = 1
4slaves = 3
5max_duration = 20 s
6log_freq = 100 ms
7cfg_file = experiments/evaluation1_dru_3_peers_1addr_1scope_mlp.conf
8
9[episode-0]
10# operations = start_send, stop_send, start_preference, stop_preference
11duration = 1 s
12op-0-operation = start_send
13op-0-src = 0
14op-0-dest = 0
15op-0-type = constant
16#op-0-period = 10 s
17op-0-base-rate= 10000
18#op-0-max-rate = 10000
19
20op-1-operation = start_send
21op-1-src = 0
22op-1-dest = 1
23op-1-type = constant
24#op-1-period = 10 s
25op-1-base-rate= 10000
26#op-1-max-rate = 10000
27
28op-2-operation = start_send
29op-2-src = 0
30op-2-dest = 2
31op-2-type = constant
32#op-1-period = 10 s
33op-2-base-rate= 10000
34#op-1-max-rate = 10000
35
36[episode-1]
37duration = 1 s
38op-0-operation = start_preference
39op-0-src = 0
40op-0-dest = 2
41op-0-type = constant
42#op-0-period = 10 s
43op-0-pref = bandwidth
44op-0-frequency = 1 s
45op-0-base-rate= 50
46#op-0-max-rate = 10000 \ No newline at end of file
diff --git a/src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_ril.conf b/src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_ril.conf
deleted file mode 100644
index 4b66e5aea..000000000
--- a/src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_ril.conf
+++ /dev/null
@@ -1,24 +0,0 @@
1@INLINE@ template_perf_ats.conf
2
3[transport]
4plugins = unix
5
6[ats]
7MODE = MLP
8UNSPECIFIED_QUOTA_IN = 128 KiB
9UNSPECIFIED_QUOTA_OUT = 128 KiB
10# LOOPBACK
11LOOPBACK_QUOTA_IN = 128 KiB
12LOOPBACK_QUOTA_OUT = 128 KiB
13# LAN
14LAN_QUOTA_IN = 128 KiB
15LAN_QUOTA_OUT = 128 KiB
16# WAN
17WAN_QUOTA_IN = 128 KiB
18WAN_QUOTA_OUT = 128 KiB
19# WLAN
20WLAN_QUOTA_IN = 128 KiB
21WLAN_QUOTA_OUT = 128 KiB
22# BLUETOOTH
23BLUETOOTH_QUOTA_IN = 128 KiB
24BLUETOOTH_QUOTA_OUT = 128 KiB \ No newline at end of file
diff --git a/src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_ril.exp b/src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_ril.exp
deleted file mode 100644
index 280b1605c..000000000
--- a/src/ats-tests/experiments/evaluation1_dru_3_peers_1addr_1scope_ril.exp
+++ /dev/null
@@ -1,46 +0,0 @@
1[experiment]
2name = sc1_eval_dru_ril
3masters = 1
4slaves = 3
5max_duration = 20 s
6log_freq = 100 ms
7cfg_file = experiments/evaluation1_dru_3_peers_1addr_1scope_ril.conf
8
9[episode-0]
10# operations = start_send, stop_send, start_preference, stop_preference
11duration = 10 s
12op-0-operation = start_send
13op-0-src = 0
14op-0-dest = 0
15op-0-type = constant
16#op-0-period = 10 s
17op-0-base-rate= 10000
18#op-0-max-rate = 10000
19
20op-1-operation = start_send
21op-1-src = 0
22op-1-dest = 1
23op-1-type = constant
24#op-1-period = 10 s
25op-1-base-rate= 10000
26#op-1-max-rate = 10000
27
28op-2-operation = start_send
29op-2-src = 0
30op-2-dest = 2
31op-2-type = constant
32#op-1-period = 10 s
33op-2-base-rate= 10000
34#op-1-max-rate = 10000
35
36[episode-1]
37duration = 10 s
38op-0-operation = start_preference
39op-0-src = 0
40op-0-dest = 2
41op-0-type = constant
42#op-0-period = 10 s
43op-0-pref = bandwidth
44op-0-frequency = 1 s
45op-0-base-rate= 50
46#op-0-max-rate = 10000 \ No newline at end of file
diff --git a/src/ats-tests/perf_ats_mlp_bandwidth.conf b/src/ats-tests/perf_ats_mlp_bandwidth.conf
deleted file mode 100644
index b803d683d..000000000
--- a/src/ats-tests/perf_ats_mlp_bandwidth.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1@INLINE@ template_perf_ats.conf
2
3[ats]
4MODE = mlp
diff --git a/src/ats-tests/perf_ats_mlp_latency.conf b/src/ats-tests/perf_ats_mlp_latency.conf
deleted file mode 100644
index b803d683d..000000000
--- a/src/ats-tests/perf_ats_mlp_latency.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1@INLINE@ template_perf_ats.conf
2
3[ats]
4MODE = mlp
diff --git a/src/ats-tests/perf_ats_mlp_none.conf b/src/ats-tests/perf_ats_mlp_none.conf
deleted file mode 100644
index b803d683d..000000000
--- a/src/ats-tests/perf_ats_mlp_none.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1@INLINE@ template_perf_ats.conf
2
3[ats]
4MODE = mlp
diff --git a/src/ats-tests/perf_ats_ril_bandwidth.conf b/src/ats-tests/perf_ats_ril_bandwidth.conf
deleted file mode 100644
index 3e7969a84..000000000
--- a/src/ats-tests/perf_ats_ril_bandwidth.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1@INLINE@ template_perf_ats.conf
2
3[ats]
4MODE = ril
diff --git a/src/ats-tests/perf_ats_ril_latency.conf b/src/ats-tests/perf_ats_ril_latency.conf
deleted file mode 100644
index 3e7969a84..000000000
--- a/src/ats-tests/perf_ats_ril_latency.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1@INLINE@ template_perf_ats.conf
2
3[ats]
4MODE = ril
diff --git a/src/ats-tests/perf_ats_ril_none.conf b/src/ats-tests/perf_ats_ril_none.conf
deleted file mode 100644
index 3e7969a84..000000000
--- a/src/ats-tests/perf_ats_ril_none.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1@INLINE@ template_perf_ats.conf
2
3[ats]
4MODE = ril
diff --git a/src/ats/Makefile.am b/src/ats/Makefile.am
index d7e5b68c7..bd8962158 100644
--- a/src/ats/Makefile.am
+++ b/src/ats/Makefile.am
@@ -15,22 +15,10 @@ if USE_COVERAGE
15endif 15endif
16 16
17lib_LTLIBRARIES = \ 17lib_LTLIBRARIES = \
18 libgnunetats.la \ 18 libgnunetats.la
19 libgnunetatsapplication.la \
20 libgnunetatstransport.la
21 19
22plugin_LTLIBRARIES = \ 20plugin_LTLIBRARIES = \
23 libgnunet_plugin_ats_proportional.la \ 21 libgnunet_plugin_ats_proportional.la
24 libgnunet_plugin_ats2_simple.la
25
26if HAVE_EXPERIMENTAL
27plugin_LTLIBRARIES += \
28 libgnunet_plugin_ats_ril.la
29if HAVE_LIBGLPK
30plugin_LTLIBRARIES += \
31 libgnunet_plugin_ats_mlp.la
32endif
33endif
34 22
35libgnunetats_la_SOURCES = \ 23libgnunetats_la_SOURCES = \
36 ats_api_connectivity.c \ 24 ats_api_connectivity.c \
@@ -45,74 +33,20 @@ libgnunetats_la_LDFLAGS = \
45 $(GN_LIB_LDFLAGS) $(WINFLAGS) \ 33 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
46 -version-info 4:0:0 34 -version-info 4:0:0
47 35
48
49libgnunetatsapplication_la_SOURCES = \
50 ats_api2_application.c
51libgnunetatsapplication_la_LIBADD = \
52 $(top_builddir)/src/util/libgnunetutil.la \
53 $(LTLIBINTL)
54libgnunetatsapplication_la_LDFLAGS = \
55 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
56 -version-info 0:0:0
57
58libgnunetatstransport_la_SOURCES = \
59 ats_api2_transport.c
60libgnunetatstransport_la_LIBADD = \
61 $(top_builddir)/src/util/libgnunetutil.la \
62 $(LTLIBINTL)
63libgnunetatstransport_la_LDFLAGS = \
64 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
65 -version-info 0:0:0
66
67libgnunet_plugin_ats_proportional_la_SOURCES = \ 36libgnunet_plugin_ats_proportional_la_SOURCES = \
68 plugin_ats_proportional.c 37 plugin_ats_proportional.c
69libgnunet_plugin_ats_proportional_la_LIBADD = \ 38libgnunet_plugin_ats_proportional_la_LIBADD = \
70 libgnunetats.la \ 39 libgnunetats.la \
71 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 40 $(top_builddir)/src/statistics/libgnunetstatistics.la \
72 $(top_builddir)/src/util/libgnunetutil.la \ 41 $(top_builddir)/src/util/libgnunetutil.la \
73 $(top_builddir)/src/nt/libgnunetnt.la \
74 $(LTLIBINTL)
75libgnunet_plugin_ats_proportional_la_LDFLAGS = \
76 $(GN_PLUGIN_LDFLAGS)
77
78libgnunet_plugin_ats2_simple_la_SOURCES = \
79 plugin_ats2_simple.c
80libgnunet_plugin_ats2_simple_la_LIBADD = \
81 $(top_builddir)/src/hello/libgnunethello.la \
82 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
83 $(top_builddir)/src/nt/libgnunetnt.la \ 42 $(top_builddir)/src/nt/libgnunetnt.la \
84 $(top_builddir)/src/statistics/libgnunetstatistics.la \
85 $(top_builddir)/src/util/libgnunetutil.la \
86 $(LTLIBINTL) 43 $(LTLIBINTL)
87libgnunet_plugin_ats2_simple_la_LDFLAGS = \ 44libgnunet_plugin_ats_proportional_la_LDFLAGS = \
88 $(GN_PLUGIN_LDFLAGS) 45 $(GN_PLUGIN_LDFLAGS)
89 46
90 47
91libgnunet_plugin_ats_mlp_la_SOURCES = \
92 plugin_ats_mlp.c
93libgnunet_plugin_ats_mlp_la_LIBADD = \
94 libgnunetats.la \
95 $(top_builddir)/src/statistics/libgnunetstatistics.la \
96 $(top_builddir)/src/nt/libgnunetnt.la \
97 $(top_builddir)/src/util/libgnunetutil.la
98libgnunet_plugin_ats_mlp_la_LDFLAGS = \
99 $(GN_PLUGIN_LDFLAGS) \
100 -lglpk
101
102libgnunet_plugin_ats_ril_la_SOURCES = \
103 plugin_ats_ril.c
104libgnunet_plugin_ats_ril_la_LIBADD = \
105 libgnunetats.la \
106 $(top_builddir)/src/statistics/libgnunetstatistics.la \
107 $(top_builddir)/src/nt/libgnunetnt.la \
108 $(top_builddir)/src/util/libgnunetutil.la \
109 $(LTLIBINTL)
110libgnunet_plugin_ats_ril_la_LDFLAGS = \
111 $(GN_PLUGIN_LDFLAGS)
112
113libexec_PROGRAMS = \ 48libexec_PROGRAMS = \
114 gnunet-service-ats \ 49 gnunet-service-ats
115 gnunet-service-ats-new
116 50
117gnunet_service_ats_SOURCES = \ 51gnunet_service_ats_SOURCES = \
118 gnunet-service-ats.c gnunet-service-ats.h \ 52 gnunet-service-ats.c gnunet-service-ats.h \
@@ -131,27 +65,10 @@ gnunet_service_ats_LDADD = \
131 libgnunetats.la \ 65 libgnunetats.la \
132 $(GN_LIBINTL) 66 $(GN_LIBINTL)
133 67
134gnunet_service_ats_new_SOURCES = \
135 gnunet-service-ats-new.c
136gnunet_service_ats_new_LDADD = \
137 $(top_builddir)/src/statistics/libgnunetstatistics.la \
138 $(top_builddir)/src/util/libgnunetutil.la \
139 $(GN_LIBINTL)
140
141
142if HAVE_TESTING 68if HAVE_TESTING
143TESTING_TESTS = \ 69TESTING_TESTS = \
144 test_ats_api_proportional \ 70 test_ats_api_proportional \
145 test_ats_reservation_api_proportional \ 71 test_ats_reservation_api_proportional
146 test_ats2_lib
147if HAVE_EXPERIMENTAL
148TESTING_TESTS += \
149 test_ats_api_ril
150if HAVE_LIBGLPK
151TESTING_TESTS += \
152 test_ats_api_mlp
153endif
154endif
155endif 72endif
156 73
157check_PROGRAMS = \ 74check_PROGRAMS = \
@@ -180,40 +97,8 @@ test_ats_reservation_api_proportional_LDADD = \
180 $(top_builddir)/src/testing/libgnunettesting.la \ 97 $(top_builddir)/src/testing/libgnunettesting.la \
181 libgnunetats.la 98 libgnunetats.la
182 99
183test_ats_api_ril_SOURCES = \
184 test_ats_api.c \
185 test_ats_lib.c test_ats_lib.h
186test_ats_api_ril_LDADD = \
187 $(top_builddir)/src/util/libgnunetutil.la \
188 $(top_builddir)/src/hello/libgnunethello.la \
189 $(top_builddir)/src/testing/libgnunettesting.la \
190 libgnunetats.la
191
192test_ats_api_mlp_SOURCES = \
193 test_ats_api.c \
194 test_ats_lib.c test_ats_lib.h
195test_ats_api_mlp_LDADD = \
196 $(top_builddir)/src/util/libgnunetutil.la \
197 $(top_builddir)/src/hello/libgnunethello.la \
198 $(top_builddir)/src/testing/libgnunettesting.la \
199 libgnunetats.la
200
201test_ats2_lib_SOURCES = \
202 test_ats2_lib.c test_ats2_lib.h
203test_ats2_lib_LDADD = \
204 $(top_builddir)/src/util/libgnunetutil.la \
205 $(top_builddir)/src/hello/libgnunethello.la \
206 $(top_builddir)/src/testing/libgnunettesting.la \
207 libgnunetatsapplication.la \
208 libgnunetatstransport.la
209
210
211EXTRA_DIST = \ 100EXTRA_DIST = \
212 ats.h ats2.h \ 101 ats.h \
213 plugin_ats2_common.c \
214 test_delay \ 102 test_delay \
215 test_ats2_lib.conf \
216 test_ats_api.conf \ 103 test_ats_api.conf \
217 test_ats_api_mlp.conf \
218 test_ats_api_ril.conf \
219 test_ats_api_proportional.conf 104 test_ats_api_proportional.conf
diff --git a/src/ats/ats2.h b/src/ats/ats2.h
deleted file mode 100644
index df402dba2..000000000
--- a/src/ats/ats2.h
+++ /dev/null
@@ -1,294 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/ats2.h
22 * @brief automatic transport selection messages
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 */
26#ifndef ATS2_H
27#define ATS2_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_ats_transport_service.h"
31
32
33GNUNET_NETWORK_STRUCT_BEGIN
34
35
36/**
37 * ATS performance characteristics for an address.
38 */
39struct PropertiesNBO
40{
41 /**
42 * Delay. Time between when the time packet is sent and the packet
43 * arrives. FOREVER if we did not (successfully) measure yet.
44 */
45 struct GNUNET_TIME_RelativeNBO delay;
46
47 /**
48 * Confirmed successful payload on this connection from this peer to
49 * the other peer. In NBO.
50 *
51 * Unit: [bytes/second]
52 */
53 uint32_t goodput_out;
54
55 /**
56 * Confirmed useful payload on this connection to this peer from
57 * the other peer. In NBO.
58 *
59 * Unit: [bytes/second]
60 */
61 uint32_t goodput_in;
62
63 /**
64 * Actual traffic on this connection from this peer to the other peer.
65 * Includes transport overhead. In NBO.
66 *
67 * Unit: [bytes/second]
68 */
69 uint32_t utilization_out;
70
71 /**
72 * Actual traffic on this connection from the other peer to this peer.
73 * Includes transport overhead. In NBO.
74 *
75 * Unit: [bytes/second]
76 */
77 uint32_t utilization_in;
78
79 /**
80 * Distance on network layer (required for distance-vector routing)
81 * in hops. Zero for direct connections (i.e. plain TCP/UDP). In NBO.
82 */
83 uint32_t distance;
84
85 /**
86 * MTU of the network layer, UINT32_MAX for no MTU (stream).
87 *
88 * Unit: [bytes]. In NBO.
89 */
90 uint32_t mtu;
91
92 /**
93 * Which network scope does the respective address belong to?
94 * A `enum GNUNET_NetworkType nt` in NBO.
95 */
96 uint32_t nt;
97
98 /**
99 * What characteristics does this communicator have?
100 * A `enum GNUNET_TRANSPORT_CommunicatorCharacteristics` in NBO.
101 */
102 uint32_t cc;
103};
104
105
106/**
107 * Application client to ATS service: we would like to have
108 * address suggestions for this peer.
109 */
110struct ExpressPreferenceMessage
111{
112 /**
113 * Type is #GNUNET_MESSAGE_TYPE_ATS_SUGGEST or
114 * #GNUNET_MESSAGE_TYPE_ATS_SUGGEST_CANCEL to stop
115 * suggestions.
116 */
117 struct GNUNET_MessageHeader header;
118
119 /**
120 * What type of performance preference does the client have?
121 * A `enum GNUNET_MQ_PreferenceKind` in NBO.
122 */
123 uint32_t pk GNUNET_PACKED;
124
125 /**
126 * Peer to get address suggestions for.
127 */
128 struct GNUNET_PeerIdentity peer;
129
130 /**
131 * How much bandwidth in bytes/second does the application expect?
132 */
133 struct GNUNET_BANDWIDTH_Value32NBO bw;
134};
135
136
137/**
138 * Transport client to ATS service: here is another session you can use.
139 */
140struct SessionAddMessage
141{
142 /**
143 * Type is #GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD or
144 * #GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY
145 */
146 struct GNUNET_MessageHeader header;
147
148 /**
149 * Internal number this client will henceforth use to
150 * refer to this session.
151 */
152 uint32_t session_id GNUNET_PACKED;
153
154 /**
155 * Identity of the peer that this session is for.
156 */
157 struct GNUNET_PeerIdentity peer;
158
159 /**
160 * Performance properties of the session.
161 */
162 struct PropertiesNBO properties;
163
164 /* followed by:
165 * - char * address (including '\0'-termination).
166 */
167};
168
169
170/**
171 * Message used to notify ATS that the performance
172 * characteristics for an session have changed.
173 */
174struct SessionUpdateMessage
175{
176 /**
177 * Message of type #GNUNET_MESSAGE_TYPE_ATS_SESSION_UPDATE.
178 */
179 struct GNUNET_MessageHeader header;
180
181 /**
182 * Internal number this client uses to refer to this session.
183 */
184 uint32_t session_id GNUNET_PACKED;
185
186 /**
187 * Which peer is this about? (Technically redundant, as the
188 * @e session_id should be sufficient, but enables ATS service
189 * to find the session faster).
190 */
191 struct GNUNET_PeerIdentity peer;
192
193 /**
194 * Performance properties of the session.
195 */
196 struct PropertiesNBO properties;
197};
198
199
200/**
201 * Message sent by ATS client to ATS service when an session
202 * was destroyed and must thus henceforth no longer be considered
203 * for scheduling.
204 */
205struct SessionDelMessage
206{
207 /**
208 * Type is #GNUNET_MESSAGE_TYPE_ATS_SESSION_DEL.
209 */
210 struct GNUNET_MessageHeader header;
211
212 /**
213 * Internal number this client uses to refer to this session.
214 */
215 uint32_t session_id GNUNET_PACKED;
216
217 /**
218 * Which peer is this about? (Technically redundant, as the
219 * @e session_id should be sufficient, but enables ATS service
220 * to find the session faster).
221 */
222 struct GNUNET_PeerIdentity peer;
223};
224
225
226/**
227 * ATS Service allocates resources to an session
228 * identified by the given @e session_id for the given @e peer with
229 * the given @e bandwidth_in and @e bandwidth_out limits from now on.
230 */
231struct SessionAllocationMessage
232{
233 /**
234 * A message of type #GNUNET_MESSAGE_TYPE_ATS_SESSION_ALLOCATION.
235 */
236 struct GNUNET_MessageHeader header;
237
238 /**
239 * Internal number this client uses to refer to the session this
240 * suggestion is about.
241 */
242 uint32_t session_id GNUNET_PACKED;
243
244 /**
245 * Which peer is this about? (Technically redundant, as the
246 * @e session_id should be sufficient, but may enable client
247 * to find the session faster and/or check consistency).
248 */
249 struct GNUNET_PeerIdentity peer;
250
251 /**
252 * How much bandwidth we are allowed for sending.
253 */
254 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
255
256 /**
257 * How much bandwidth we are allowed for receiving.
258 */
259 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
260};
261
262
263/**
264 * ATS Service suggests to the transport service to try the address
265 * for the given @e peer.
266 */
267struct AddressSuggestionMessage
268{
269 /**
270 * A message of type #GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION.
271 */
272 struct GNUNET_MessageHeader header;
273
274 /**
275 * Zero.
276 */
277 uint32_t reserved GNUNET_PACKED;
278
279 /**
280 * Which peer is this about? (Technically redundant, as the
281 * @e session_id should be sufficient, but may enable client
282 * to find the session faster and/or check consistency).
283 */
284 struct GNUNET_PeerIdentity peer;
285
286 /* Followed by 0-terminated address */
287};
288
289
290GNUNET_NETWORK_STRUCT_END
291
292
293
294#endif
diff --git a/src/ats/ats_api2_application.c b/src/ats/ats_api2_application.c
deleted file mode 100644
index 46e57c5bb..000000000
--- a/src/ats/ats_api2_application.c
+++ /dev/null
@@ -1,366 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/ats_api2_application.c
22 * @brief enable clients to ask ATS about establishing connections to peers
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 */
26#include "platform.h"
27#include "gnunet_ats_application_service.h"
28#include "ats2.h"
29
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "ats-application-api", \
32 __VA_ARGS__)
33
34
35/**
36 * Handle for ATS address suggestion requests.
37 */
38struct GNUNET_ATS_ApplicationSuggestHandle
39{
40 /**
41 * ID of the peer for which address suggestion was requested.
42 */
43 struct GNUNET_PeerIdentity id;
44
45 /**
46 * Connecitivity handle this suggestion handle belongs to.
47 */
48 struct GNUNET_ATS_ApplicationHandle *ch;
49
50 /**
51 * What preference is being expressed?
52 */
53 enum GNUNET_MQ_PreferenceKind pk;
54
55 /**
56 * How much bandwidth does the client expect?
57 */
58 struct GNUNET_BANDWIDTH_Value32NBO bw;
59};
60
61
62/**
63 * Handle to the ATS subsystem for application management.
64 */
65struct GNUNET_ATS_ApplicationHandle
66{
67 /**
68 * Our configuration.
69 */
70 const struct GNUNET_CONFIGURATION_Handle *cfg;
71
72 /**
73 * Map with the identities of all the peers for which we would
74 * like to have address suggestions. The key is the PID, the
75 * value is currently the `struct GNUNET_ATS_ApplicationSuggestHandle`
76 */
77 struct GNUNET_CONTAINER_MultiPeerMap *sug_requests;
78
79 /**
80 * Message queue for sending requests to the ATS service.
81 */
82 struct GNUNET_MQ_Handle *mq;
83
84 /**
85 * Task to trigger reconnect.
86 */
87 struct GNUNET_SCHEDULER_Task *task;
88
89 /**
90 * Reconnect backoff delay.
91 */
92 struct GNUNET_TIME_Relative backoff;
93};
94
95
96/**
97 * Re-establish the connection to the ATS service.
98 *
99 * @param ch handle to use to re-connect.
100 */
101static void
102reconnect (struct GNUNET_ATS_ApplicationHandle *ch);
103
104
105/**
106 * Re-establish the connection to the ATS service.
107 *
108 * @param cls handle to use to re-connect.
109 */
110static void
111reconnect_task (void *cls)
112{
113 struct GNUNET_ATS_ApplicationHandle *ch = cls;
114
115 ch->task = NULL;
116 reconnect (ch);
117}
118
119
120/**
121 * Disconnect from ATS and then reconnect.
122 *
123 * @param ch our handle
124 */
125static void
126force_reconnect (struct GNUNET_ATS_ApplicationHandle *ch)
127{
128 if (NULL != ch->mq)
129 {
130 GNUNET_MQ_destroy (ch->mq);
131 ch->mq = NULL;
132 }
133 ch->backoff = GNUNET_TIME_STD_BACKOFF (ch->backoff);
134 ch->task = GNUNET_SCHEDULER_add_delayed (ch->backoff,
135 &reconnect_task,
136 ch);
137}
138
139
140/**
141 * We encountered an error handling the MQ to the
142 * ATS service. Reconnect.
143 *
144 * @param cls the `struct GNUNET_ATS_ApplicationHandle`
145 * @param error details about the error
146 */
147static void
148error_handler (void *cls,
149 enum GNUNET_MQ_Error error)
150{
151 struct GNUNET_ATS_ApplicationHandle *ch = cls;
152
153 LOG (GNUNET_ERROR_TYPE_DEBUG,
154 "ATS connection died (code %d), reconnecting\n",
155 (int) error);
156 force_reconnect (ch);
157}
158
159
160/**
161 * Transmit request for an address suggestion.
162 *
163 * @param cls the `struct GNUNET_ATS_ApplicationHandle`
164 * @param peer peer to ask for an address suggestion for
165 * @param value the `struct GNUNET_ATS_SuggestHandle`
166 * @return #GNUNET_OK (continue to iterate), #GNUNET_SYSERR on
167 * failure (message queue no longer exists)
168 */
169static int
170transmit_suggestion (void *cls,
171 const struct GNUNET_PeerIdentity *peer,
172 void *value)
173{
174 struct GNUNET_ATS_ApplicationHandle *ch = cls;
175 struct GNUNET_ATS_ApplicationSuggestHandle *sh = value;
176 struct GNUNET_MQ_Envelope *ev;
177 struct ExpressPreferenceMessage *m;
178
179 if (NULL == ch->mq)
180 return GNUNET_SYSERR;
181 ev = GNUNET_MQ_msg (m,
182 GNUNET_MESSAGE_TYPE_ATS_SUGGEST);
183 m->pk = htonl ((uint32_t) sh->pk);
184 m->bw = sh->bw;
185 m->peer = *peer;
186 GNUNET_MQ_send (ch->mq, ev);
187 return GNUNET_OK;
188}
189
190
191/**
192 * Re-establish the connection to the ATS service.
193 *
194 * @param ch handle to use to re-connect.
195 */
196static void
197reconnect (struct GNUNET_ATS_ApplicationHandle *ch)
198{
199 static const struct GNUNET_MQ_MessageHandler handlers[] = {
200 { NULL, 0, 0 }
201 };
202
203 GNUNET_assert (NULL == ch->mq);
204 ch->mq = GNUNET_CLIENT_connect (ch->cfg,
205 "ats",
206 handlers,
207 &error_handler,
208 ch);
209 if (NULL == ch->mq)
210 {
211 force_reconnect (ch);
212 return;
213 }
214 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
215 &transmit_suggestion,
216 ch);
217}
218
219
220/**
221 * Initialize the ATS application suggestion client handle.
222 *
223 * @param cfg configuration to use
224 * @return ats application handle, NULL on error
225 */
226struct GNUNET_ATS_ApplicationHandle *
227GNUNET_ATS_application_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
228{
229 struct GNUNET_ATS_ApplicationHandle *ch;
230
231 ch = GNUNET_new (struct GNUNET_ATS_ApplicationHandle);
232 ch->cfg = cfg;
233 ch->sug_requests = GNUNET_CONTAINER_multipeermap_create (32,
234 GNUNET_YES);
235 reconnect (ch);
236 return ch;
237}
238
239
240/**
241 * Function called to free all `struct GNUNET_ATS_ApplicationSuggestHandle`s
242 * in the map.
243 *
244 * @param cls NULL
245 * @param key the key
246 * @param value the value to free
247 * @return #GNUNET_OK (continue to iterate)
248 */
249static int
250free_sug_handle (void *cls,
251 const struct GNUNET_PeerIdentity *key,
252 void *value)
253{
254 struct GNUNET_ATS_ApplicationSuggestHandle *cur = value;
255
256 GNUNET_free (cur);
257 return GNUNET_OK;
258}
259
260
261/**
262 * Client is done with ATS application management, release resources.
263 *
264 * @param ch handle to release
265 */
266void
267GNUNET_ATS_application_done (struct GNUNET_ATS_ApplicationHandle *ch)
268{
269 if (NULL != ch->mq)
270 {
271 GNUNET_MQ_destroy (ch->mq);
272 ch->mq = NULL;
273 }
274 if (NULL != ch->task)
275 {
276 GNUNET_SCHEDULER_cancel (ch->task);
277 ch->task = NULL;
278 }
279 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
280 &free_sug_handle,
281 NULL);
282 GNUNET_CONTAINER_multipeermap_destroy (ch->sug_requests);
283 GNUNET_free (ch);
284}
285
286
287/**
288 * We would like to receive address suggestions for a peer. ATS will
289 * respond with a call to the continuation immediately containing an address or
290 * no address if none is available. ATS can suggest more addresses until we call
291 * #GNUNET_ATS_application_suggest_cancel().
292 *
293 * @param ch handle
294 * @param peer identity of the peer we need an address for
295 * @param pk what kind of application will the application require (can be
296 * #GNUNET_MQ_PREFERENCE_NONE, we will still try to connect)
297 * @param bw desired bandwith, can be zero (we will still try to connect)
298 * @return suggest handle, NULL if a request is already pending
299 */
300struct GNUNET_ATS_ApplicationSuggestHandle *
301GNUNET_ATS_application_suggest (struct GNUNET_ATS_ApplicationHandle *ch,
302 const struct GNUNET_PeerIdentity *peer,
303 enum GNUNET_MQ_PreferenceKind pk,
304 struct GNUNET_BANDWIDTH_Value32NBO bw)
305{
306 struct GNUNET_ATS_ApplicationSuggestHandle *s;
307
308 s = GNUNET_new (struct GNUNET_ATS_ApplicationSuggestHandle);
309 s->ch = ch;
310 s->id = *peer;
311 s->pk = pk;
312 s->bw = bw;
313 (void) GNUNET_CONTAINER_multipeermap_put (ch->sug_requests,
314 &s->id,
315 s,
316 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
317 LOG (GNUNET_ERROR_TYPE_DEBUG,
318 "Requesting ATS to suggest address for `%s'\n",
319 GNUNET_i2s (peer));
320 if (NULL == ch->mq)
321 return s;
322 GNUNET_assert (GNUNET_OK ==
323 transmit_suggestion (ch,
324 &s->id,
325 s));
326 return s;
327}
328
329
330/**
331 * We no longer care about being connected to a peer.
332 *
333 * @param sh handle to stop
334 */
335void
336GNUNET_ATS_application_suggest_cancel (struct
337 GNUNET_ATS_ApplicationSuggestHandle *sh)
338{
339 struct GNUNET_ATS_ApplicationHandle *ch = sh->ch;
340 struct GNUNET_MQ_Envelope *ev;
341 struct ExpressPreferenceMessage *m;
342
343 LOG (GNUNET_ERROR_TYPE_DEBUG,
344 "Telling ATS we no longer care for an address for `%s'\n",
345 GNUNET_i2s (&sh->id));
346 GNUNET_assert (GNUNET_OK ==
347 GNUNET_CONTAINER_multipeermap_remove (ch->sug_requests,
348 &sh->id,
349 sh));
350 if (NULL == ch->mq)
351 {
352 GNUNET_free (sh);
353 return;
354 }
355 ev = GNUNET_MQ_msg (m,
356 GNUNET_MESSAGE_TYPE_ATS_SUGGEST_CANCEL);
357 m->pk = htonl ((uint32_t) sh->pk);
358 m->bw = sh->bw;
359 m->peer = sh->id;
360 GNUNET_MQ_send (ch->mq,
361 ev);
362 GNUNET_free (sh);
363}
364
365
366/* end of ats_api2_application.c */
diff --git a/src/ats/ats_api2_transport.c b/src/ats/ats_api2_transport.c
deleted file mode 100644
index da02ca592..000000000
--- a/src/ats/ats_api2_transport.c
+++ /dev/null
@@ -1,689 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015, 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/ats_api2_transport.c
22 * @brief address suggestions and bandwidth allocation
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 */
26#include "platform.h"
27#include "gnunet_ats_transport_service.h"
28#include "ats2.h"
29
30#define LOG(kind, ...) GNUNET_log_from (kind, "ats-transport-api", __VA_ARGS__)
31
32
33/**
34 * Information we track per session, incoming or outgoing. It also
35 * doesn't matter if we have a session, any session that ATS is
36 * allowed to suggest right now should be tracked.
37 */
38struct GNUNET_ATS_SessionRecord
39{
40 /**
41 * Transport handle this session record belongs to.
42 */
43 struct GNUNET_ATS_TransportHandle *ath;
44
45 /**
46 * Address data.
47 */
48 const char *address;
49
50 /**
51 * Session handle, NULL if inbound-only (also implies we cannot
52 * actually control inbound traffic via transport!). So if
53 * @e session is NULL, the @e properties are informative for
54 * ATS (connection exists, utilization) but ATS cannot directly
55 * influence it (and should thus not call the
56 * #GNUNET_ATS_AllocationCallback for this @e session, which is
57 * obvious as NULL is not a meaningful session to allocation
58 * resources to).
59 */
60 struct GNUNET_ATS_Session *session;
61
62 /**
63 * Identity of the peer reached at @e address.
64 */
65 struct GNUNET_PeerIdentity pid;
66
67 /**
68 * Performance data about the @e session.
69 */
70 struct GNUNET_ATS_Properties properties;
71
72 /**
73 * Unique ID to identify this session at this @a pid in IPC
74 * messages.
75 */
76 uint32_t slot;
77};
78
79
80/**
81 * Handle to the ATS subsystem for bandwidth/transport transport information.
82 */
83struct GNUNET_ATS_TransportHandle
84{
85 /**
86 * Our configuration.
87 */
88 const struct GNUNET_CONFIGURATION_Handle *cfg;
89
90 /**
91 * Callback to invoke on suggestions.
92 */
93 GNUNET_ATS_SuggestionCallback suggest_cb;
94
95 /**
96 * Closure for @e suggest_cb.
97 */
98 void *suggest_cb_cls;
99
100 /**
101 * Callback to invoke on allocations.
102 */
103 GNUNET_ATS_AllocationCallback alloc_cb;
104
105 /**
106 * Closure for @e alloc_cb.
107 */
108 void *alloc_cb_cls;
109
110 /**
111 * Message queue for sending requests to the ATS service.
112 */
113 struct GNUNET_MQ_Handle *mq;
114
115 /**
116 * Task to trigger reconnect.
117 */
118 struct GNUNET_SCHEDULER_Task *task;
119
120 /**
121 * Hash map mapping PIDs to session records.
122 */
123 struct GNUNET_CONTAINER_MultiPeerMap *records;
124
125 /**
126 * Reconnect backoff delay.
127 */
128 struct GNUNET_TIME_Relative backoff;
129};
130
131
132
133/**
134 * Convert ATS properties from host to network byte order.
135 *
136 * @param nbo[OUT] value written
137 * @param hbo value read
138 */
139static void
140properties_hton (struct PropertiesNBO *nbo,
141 const struct GNUNET_ATS_Properties *hbo)
142{
143 nbo->delay = GNUNET_TIME_relative_hton (hbo->delay);
144 nbo->goodput_out = htonl (hbo->goodput_out);
145 nbo->goodput_in = htonl (hbo->goodput_in);
146 nbo->utilization_out = htonl (hbo->utilization_out);
147 nbo->utilization_in = htonl (hbo->utilization_in);
148 nbo->distance = htonl (hbo->distance);
149 nbo->mtu = htonl (hbo->mtu);
150 nbo->nt = htonl ((uint32_t) hbo->nt);
151 nbo->cc = htonl ((uint32_t) hbo->cc);
152}
153
154
155/**
156 * Re-establish the connection to the ATS service.
157 *
158 * @param sh handle to use to re-connect.
159 */
160static void
161reconnect (struct GNUNET_ATS_TransportHandle *ath);
162
163
164/**
165 * Re-establish the connection to the ATS service.
166 *
167 * @param cls handle to use to re-connect.
168 */
169static void
170reconnect_task (void *cls)
171{
172 struct GNUNET_ATS_TransportHandle *ath = cls;
173
174 ath->task = NULL;
175 reconnect (ath);
176}
177
178
179/**
180 * Disconnect from ATS and then reconnect.
181 *
182 * @param ath our handle
183 */
184static void
185force_reconnect (struct GNUNET_ATS_TransportHandle *ath)
186{
187 if (NULL != ath->mq)
188 {
189 GNUNET_MQ_destroy (ath->mq);
190 ath->mq = NULL;
191 }
192 /* FIXME: do we tell transport service about disconnect events? CON:
193 initially ATS will have a really screwed picture of the world and
194 the rapid change would be bad. PRO: if we don't, ATS and
195 transport may disagree about the allocation for a while...
196 For now: lazy: do nothing. */
197 ath->backoff = GNUNET_TIME_STD_BACKOFF (ath->backoff);
198 ath->task = GNUNET_SCHEDULER_add_delayed (ath->backoff,
199 &reconnect_task,
200 ath);
201}
202
203
204/**
205 * Check format of address suggestion message from the service.
206 *
207 * @param cls the `struct GNUNET_ATS_TransportHandle`
208 * @param m message received
209 */
210static int
211check_ats_address_suggestion (void *cls,
212 const struct AddressSuggestionMessage *m)
213{
214 (void) cls;
215 GNUNET_MQ_check_zero_termination (m);
216 return GNUNET_SYSERR;
217}
218
219
220/**
221 * We received an address suggestion message from the service.
222 *
223 * @param cls the `struct GNUNET_ATS_TransportHandle`
224 * @param m message received
225 */
226static void
227handle_ats_address_suggestion (void *cls,
228 const struct AddressSuggestionMessage *m)
229{
230 struct GNUNET_ATS_TransportHandle *ath = cls;
231 const char *address = (const char *) &m[1];
232
233 ath->suggest_cb (ath->suggest_cb_cls,
234 &m->peer,
235 address);
236}
237
238
239/**
240 * Closure for #match_session_cb.
241 */
242struct FindContext
243{
244 /**
245 * Key to look for.
246 */
247 uint32_t session_id;
248
249 /**
250 * Where to store the result.
251 */
252 struct GNUNET_ATS_SessionRecord *sr;
253};
254
255
256/**
257 * Finds matching session record.
258 *
259 * @param cls a `struct FindContext`
260 * @param pid peer identity (unused)
261 * @param value a `struct GNUNET_ATS_SessionRecord`
262 * @return #GNUNET_NO if match found, #GNUNET_YES to continue searching
263 */
264static int
265match_session_cb (void *cls,
266 const struct GNUNET_PeerIdentity *pid,
267 void *value)
268{
269 struct FindContext *fc = cls;
270 struct GNUNET_ATS_SessionRecord *sr = value;
271
272 (void) pid;
273 if (fc->session_id == sr->slot)
274 {
275 fc->sr = sr;
276 return GNUNET_NO;
277 }
278 return GNUNET_YES;
279}
280
281
282
283/**
284 * Find session record for peer @a pid and session @a session_id
285 *
286 * @param ath transport handle to search
287 * @param session_id session ID to match
288 * @param pid peer to search under
289 * @return NULL if no such record exists
290 */
291static struct GNUNET_ATS_SessionRecord *
292find_session (struct GNUNET_ATS_TransportHandle *ath,
293 uint32_t session_id,
294 const struct GNUNET_PeerIdentity *pid)
295{
296 struct FindContext fc = {
297 .session_id = session_id,
298 .sr = NULL
299 };
300
301 GNUNET_CONTAINER_multipeermap_get_multiple (ath->records,
302 pid,
303 &match_session_cb,
304 &fc);
305 return fc.sr;
306}
307
308
309/**
310 * We received a session allocation message from the service.
311 *
312 * @param cls the `struct GNUNET_ATS_TransportHandle`
313 * @param m message received
314 */
315static void
316handle_ats_session_allocation (void *cls,
317 const struct SessionAllocationMessage *m)
318{
319 struct GNUNET_ATS_TransportHandle *ath = cls;
320 struct GNUNET_ATS_SessionRecord *ar;
321 uint32_t session_id;
322
323 session_id = ntohl (m->session_id);
324 ar = find_session (ath,
325 session_id,
326 &m->peer);
327 if (NULL == ar)
328 {
329 /* this can (rarely) happen if ATS changes an sessiones allocation
330 just when the transport service deleted it */
331 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
332 "Allocation ignored, session unknown\n");
333 return;
334 }
335 ath->backoff = GNUNET_TIME_UNIT_ZERO;
336 LOG (GNUNET_ERROR_TYPE_DEBUG,
337 "ATS allocates bandwidth for peer `%s' using address %s\n",
338 GNUNET_i2s (&ar->pid),
339 ar->address);
340 ath->alloc_cb (ath->alloc_cb_cls,
341 ar->session,
342 m->bandwidth_out,
343 m->bandwidth_in);
344}
345
346
347/**
348 * We encountered an error handling the MQ to the ATS service.
349 * Reconnect.
350 *
351 * @param cls the `struct GNUNET_ATS_TransportHandle`
352 * @param error details about the error
353 */
354static void
355error_handler (void *cls,
356 enum GNUNET_MQ_Error error)
357{
358 struct GNUNET_ATS_TransportHandle *ath = cls;
359
360 LOG (GNUNET_ERROR_TYPE_DEBUG,
361 "ATS connection died (code %d), reconnecting\n",
362 (int) error);
363 force_reconnect (ath);
364}
365
366
367/**
368 * Generate and transmit the `struct SessionAddMessage` for the given
369 * session record.
370 *
371 * @param ar the session to inform the ATS service about
372 */
373static void
374send_add_session_message (const struct GNUNET_ATS_SessionRecord *ar)
375{
376 struct GNUNET_ATS_TransportHandle *ath = ar->ath;
377 struct GNUNET_MQ_Envelope *ev;
378 struct SessionAddMessage *m;
379 size_t alen;
380
381 if (NULL == ath->mq)
382 return; /* disconnected, skip for now */
383 alen = strlen (ar->address) + 1;
384 ev = GNUNET_MQ_msg_extra (m,
385 alen,
386 (NULL == ar->session)
387 ? GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY
388 : GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD);
389 m->peer = ar->pid;
390 m->session_id = htonl (ar->slot);
391 properties_hton (&m->properties,
392 &ar->properties);
393 GNUNET_memcpy (&m[1],
394 ar->address,
395 alen);
396
397 LOG (GNUNET_ERROR_TYPE_DEBUG,
398 "Adding address `%s' for peer `%s'\n",
399 ar->address,
400 GNUNET_i2s (&ar->pid));
401 GNUNET_MQ_send (ath->mq,
402 ev);
403}
404
405
406/**
407 * Send ATS information about the session record.
408 *
409 * @param cls our `struct GNUNET_ATS_TransportHandle *`, unused
410 * @param pid unused
411 * @param value the `struct GNUNET_ATS_SessionRecord *` to add
412 * @return #GNUNET_OK
413 */
414static int
415send_add_session_cb (void *cls,
416 const struct GNUNET_PeerIdentity *pid,
417 void *value)
418{
419 struct GNUNET_ATS_SessionRecord *ar = value;
420
421 (void) cls;
422 (void) pid;
423 send_add_session_message (ar);
424 return GNUNET_OK;
425}
426
427
428/**
429 * Re-establish the connection to the ATS service.
430 *
431 * @param ath handle to use to re-connect.
432 */
433static void
434reconnect (struct GNUNET_ATS_TransportHandle *ath)
435{
436 struct GNUNET_MQ_MessageHandler handlers[] = {
437 GNUNET_MQ_hd_var_size (ats_address_suggestion,
438 GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION,
439 struct AddressSuggestionMessage,
440 ath),
441 GNUNET_MQ_hd_fixed_size (ats_session_allocation,
442 GNUNET_MESSAGE_TYPE_ATS_SESSION_ALLOCATION,
443 struct SessionAllocationMessage,
444 ath),
445 GNUNET_MQ_handler_end ()
446 };
447 struct GNUNET_MQ_Envelope *ev;
448 struct GNUNET_MessageHeader *init;
449
450 GNUNET_assert (NULL == ath->mq);
451 ath->mq = GNUNET_CLIENT_connect (ath->cfg,
452 "ats",
453 handlers,
454 &error_handler,
455 ath);
456 if (NULL == ath->mq)
457 {
458 GNUNET_break (0);
459 force_reconnect (ath);
460 return;
461 }
462 ev = GNUNET_MQ_msg (init,
463 GNUNET_MESSAGE_TYPE_ATS_START);
464 GNUNET_MQ_send (ath->mq,
465 ev);
466 if (NULL == ath->mq)
467 return;
468 GNUNET_CONTAINER_multipeermap_iterate (ath->records,
469 &send_add_session_cb,
470 ath);
471}
472
473
474/**
475 * Initialize the ATS subsystem.
476 *
477 * @param cfg configuration to use
478 * @param alloc_cb notification to call whenever the allocation changed
479 * @param alloc_cb_cls closure for @a alloc_cb
480 * @param suggest_cb notification to call whenever the suggestation is made
481 * @param suggest_cb_cls closure for @a suggest_cb
482 * @return ats context
483 */
484struct GNUNET_ATS_TransportHandle *
485GNUNET_ATS_transport_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
486 GNUNET_ATS_AllocationCallback alloc_cb,
487 void *alloc_cb_cls,
488 GNUNET_ATS_SuggestionCallback suggest_cb,
489 void *suggest_cb_cls)
490{
491 struct GNUNET_ATS_TransportHandle *ath;
492
493 ath = GNUNET_new (struct GNUNET_ATS_TransportHandle);
494 ath->cfg = cfg;
495 ath->suggest_cb = suggest_cb;
496 ath->suggest_cb_cls = suggest_cb_cls;
497 ath->alloc_cb = alloc_cb;
498 ath->alloc_cb_cls = alloc_cb_cls;
499 ath->records = GNUNET_CONTAINER_multipeermap_create (128,
500 GNUNET_YES);
501 reconnect (ath);
502 return ath;
503}
504
505
506/**
507 * Release memory associated with the session record.
508 *
509 * @param cls NULL
510 * @param pid unused
511 * @param value a `struct GNUNET_ATS_SessionRecord`
512 * @return #GNUNET_OK
513 */
514static int
515free_record (void *cls,
516 const struct GNUNET_PeerIdentity *pid,
517 void *value)
518{
519 struct GNUNET_ATS_SessionRecord *ar = value;
520
521 (void) cls;
522 (void) pid;
523 GNUNET_free (ar);
524 return GNUNET_OK;
525}
526
527
528/**
529 * Client is done with ATS transport, release resources.
530 *
531 * @param ath handle to release
532 */
533void
534GNUNET_ATS_transport_done (struct GNUNET_ATS_TransportHandle *ath)
535{
536 if (NULL != ath->mq)
537 {
538 GNUNET_MQ_destroy (ath->mq);
539 ath->mq = NULL;
540 }
541 if (NULL != ath->task)
542 {
543 GNUNET_SCHEDULER_cancel (ath->task);
544 ath->task = NULL;
545 }
546 GNUNET_CONTAINER_multipeermap_iterate (ath->records,
547 &free_record,
548 NULL);
549 GNUNET_CONTAINER_multipeermap_destroy (ath->records);
550 GNUNET_free (ath);
551}
552
553
554/**
555 * We have a new session ATS should know. Sessiones have to be added
556 * with this function before they can be: updated, set in use and
557 * destroyed.
558 *
559 * @param ath handle
560 * @param pid peer we connected to
561 * @param address the address (human readable version)
562 * @param session transport-internal handle for the session/queue, NULL if
563 * the session is inbound-only
564 * @param prop performance data for the session
565 * @return handle to the session representation inside ATS, NULL
566 * on error (i.e. ATS knows this exact session already)
567 */
568struct GNUNET_ATS_SessionRecord *
569GNUNET_ATS_session_add (struct GNUNET_ATS_TransportHandle *ath,
570 const struct GNUNET_PeerIdentity *pid,
571 const char *address,
572 struct GNUNET_ATS_Session *session,
573 const struct GNUNET_ATS_Properties *prop)
574{
575 struct GNUNET_ATS_SessionRecord *ar;
576 uint32_t s;
577 size_t alen;
578
579 if (NULL == address)
580 {
581 /* we need a valid address */
582 GNUNET_break (0);
583 return NULL;
584 }
585 alen = strlen (address) + 1;
586 if ((alen + sizeof(struct SessionAddMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
587 (alen >= GNUNET_MAX_MESSAGE_SIZE))
588 {
589 /* address too large for us, this should not happen */
590 GNUNET_break (0);
591 return NULL;
592 }
593
594 /* Spin 's' until we find an unused session ID for this pid */
595 for (s = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
596 UINT32_MAX);
597 NULL != find_session (ath,
598 s,
599 pid);
600 s++)
601 ;
602
603 alen = strlen (address) + 1;
604 ar = GNUNET_malloc (sizeof(struct GNUNET_ATS_SessionRecord) + alen);
605 ar->ath = ath;
606 ar->slot = s;
607 ar->session = session;
608 ar->address = (const char *) &ar[1];
609 ar->pid = *pid;
610 ar->properties = *prop;
611 memcpy (&ar[1],
612 address,
613 alen);
614 (void) GNUNET_CONTAINER_multipeermap_put (ath->records,
615 &ar->pid,
616 ar,
617 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
618 send_add_session_message (ar);
619 return ar;
620}
621
622
623/**
624 * We have updated performance statistics for a given session. Note
625 * that this function can be called for sessiones that are currently
626 * in use as well as sessiones that are valid but not actively in use.
627 * Furthermore, the peer may not even be connected to us right now (in
628 * which case the call may be ignored or the information may be stored
629 * for later use). Update bandwidth assignments.
630 *
631 * @param ar session record to update information for
632 * @param prop performance data for the session
633 */
634void
635GNUNET_ATS_session_update (struct GNUNET_ATS_SessionRecord *ar,
636 const struct GNUNET_ATS_Properties *prop)
637{
638 struct GNUNET_ATS_TransportHandle *ath = ar->ath;
639 struct GNUNET_MQ_Envelope *ev;
640 struct SessionUpdateMessage *m;
641
642 LOG (GNUNET_ERROR_TYPE_DEBUG,
643 "Updating address `%s' for peer `%s'\n",
644 ar->address,
645 GNUNET_i2s (&ar->pid));
646 ar->properties = *prop;
647 if (NULL == ath->mq)
648 return; /* disconnected, skip for now */
649 ev = GNUNET_MQ_msg (m,
650 GNUNET_MESSAGE_TYPE_ATS_SESSION_UPDATE);
651 m->session_id = htonl (ar->slot);
652 m->peer = ar->pid;
653 properties_hton (&m->properties,
654 &ar->properties);
655 GNUNET_MQ_send (ath->mq,
656 ev);
657}
658
659
660/**
661 * A session was destroyed, ATS should now schedule and
662 * allocate under the assumption that this @a ar is no
663 * longer in use.
664 *
665 * @param ar session record to drop
666 */
667void
668GNUNET_ATS_session_del (struct GNUNET_ATS_SessionRecord *ar)
669{
670 struct GNUNET_ATS_TransportHandle *ath = ar->ath;
671 struct GNUNET_MQ_Envelope *ev;
672 struct SessionDelMessage *m;
673
674 LOG (GNUNET_ERROR_TYPE_DEBUG,
675 "Deleting address `%s' for peer `%s'\n",
676 ar->address,
677 GNUNET_i2s (&ar->pid));
678 if (NULL == ath->mq)
679 return;
680 ev = GNUNET_MQ_msg (m,
681 GNUNET_MESSAGE_TYPE_ATS_SESSION_DEL);
682 m->session_id = htonl (ar->slot);
683 m->peer = ar->pid;
684 GNUNET_MQ_send (ath->mq,
685 ev);
686}
687
688
689/* end of ats_api2_transport.c */
diff --git a/src/ats/gnunet-service-ats-new.c b/src/ats/gnunet-service-ats-new.c
deleted file mode 100644
index f2ef92436..000000000
--- a/src/ats/gnunet-service-ats-new.c
+++ /dev/null
@@ -1,804 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011, 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/gnunet-service-ats-new.c
22 * @brief ats service
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_statistics_service.h"
29#include "gnunet_ats_plugin_new.h"
30#include "ats2.h"
31
32
33/**
34 * What type of client is this client?
35 */
36enum ClientType
37{
38 /**
39 * We don't know yet.
40 */
41 CT_NONE = 0,
42
43 /**
44 * Transport service.
45 */
46 CT_TRANSPORT,
47
48 /**
49 * Application.
50 */
51 CT_APPLICATION
52};
53
54
55/**
56 * Information we track per client.
57 */
58struct Client;
59
60/**
61 * Preferences expressed by a client are kept in a DLL per client.
62 */
63struct ClientPreference
64{
65 /**
66 * DLL pointer.
67 */
68 struct ClientPreference *next;
69
70 /**
71 * DLL pointer.
72 */
73 struct ClientPreference *prev;
74
75 /**
76 * Which client expressed the preference?
77 */
78 struct Client *client;
79
80 /**
81 * Plugin's representation of the preference.
82 */
83 struct GNUNET_ATS_PreferenceHandle *ph;
84
85 /**
86 * Details about the preference.
87 */
88 struct GNUNET_ATS_Preference pref;
89};
90
91
92/**
93 * Information about ongoing sessions of the transport client.
94 */
95struct GNUNET_ATS_Session
96{
97 /**
98 * Session data exposed to the plugin.
99 */
100 struct GNUNET_ATS_SessionData data;
101
102 /**
103 * The transport client that provided the session.
104 */
105 struct Client *client;
106
107 /**
108 * Session state in the plugin.
109 */
110 struct GNUNET_ATS_SessionHandle *sh;
111
112 /**
113 * Unique ID for the session when talking with the client.
114 */
115 uint32_t session_id;
116};
117
118
119/**
120 * Information we track per client.
121 */
122struct Client
123{
124 /**
125 * Type of the client, initially #CT_NONE.
126 */
127 enum ClientType type;
128
129 /**
130 * Service handle of the client.
131 */
132 struct GNUNET_SERVICE_Client *client;
133
134 /**
135 * Message queue to talk to the client.
136 */
137 struct GNUNET_MQ_Handle *mq;
138
139 /**
140 * Details depending on @e type.
141 */
142 union
143 {
144 struct
145 {
146 /**
147 * Head of DLL of preferences expressed by this client.
148 */
149 struct ClientPreference *cp_head;
150
151 /**
152 * Tail of DLL of preferences expressed by this client.
153 */
154 struct ClientPreference *cp_tail;
155 } application;
156
157 struct
158 {
159 /**
160 * Map from session IDs to `struct GNUNET_ATS_Session` objects.
161 */
162 struct GNUNET_CONTAINER_MultiHashMap32 *sessions;
163 } transport;
164 } details;
165};
166
167
168/**
169 * Handle for statistics.
170 */
171static struct GNUNET_STATISTICS_Handle *stats;
172
173/**
174 * Our solver.
175 */
176static struct GNUNET_ATS_SolverFunctions *plugin;
177
178/**
179 * Solver plugin name as string
180 */
181static char *plugin_name;
182
183/**
184 * The transport client (there can only be one at a time).
185 */
186static struct Client *transport_client;
187
188
189/**
190 * Function called by the solver to prompt the transport to
191 * try out a new address.
192 *
193 * @param cls closure, NULL
194 * @param pid peer this is about
195 * @param address address the transport should try
196 */
197static void
198suggest_cb (void *cls,
199 const struct GNUNET_PeerIdentity *pid,
200 const char *address)
201{
202 struct GNUNET_MQ_Envelope *env;
203 size_t slen = strlen (address) + 1;
204 struct AddressSuggestionMessage *as;
205
206 if (NULL == transport_client)
207 {
208 // FIXME: stats!
209 return;
210 }
211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
212 "Suggesting address `%s' of peer `%s'\n",
213 address,
214 GNUNET_i2s (pid));
215 env = GNUNET_MQ_msg_extra (as,
216 slen,
217 GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION);
218 as->peer = *pid;
219 memcpy (&as[1],
220 address,
221 slen);
222 GNUNET_MQ_send (transport_client->mq,
223 env);
224}
225
226
227/**
228 * Function called by the solver to tell the transpor to
229 * allocate bandwidth for the specified session.
230 *
231 * @param cls closure, NULL
232 * @param session session this is about
233 * @param peer peer this is about
234 * @param bw_in suggested bandwidth for receiving
235 * @param bw_out suggested bandwidth for transmission
236 */
237static void
238allocate_cb (void *cls,
239 struct GNUNET_ATS_Session *session,
240 const struct GNUNET_PeerIdentity *peer,
241 struct GNUNET_BANDWIDTH_Value32NBO bw_in,
242 struct GNUNET_BANDWIDTH_Value32NBO bw_out)
243{
244 struct GNUNET_MQ_Envelope *env;
245 struct SessionAllocationMessage *sam;
246
247 (void) cls;
248 if ((NULL == transport_client) ||
249 (session->client != transport_client))
250 {
251 /* transport must have just died and solver is addressing the
252 losses of sessions (possibly of previous transport), ignore! */
253 return;
254 }
255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
256 "Allocating %u/%u bytes for %p of peer `%s'\n",
257 ntohl (bw_in.value__),
258 ntohl (bw_out.value__),
259 session,
260 GNUNET_i2s (peer));
261 env = GNUNET_MQ_msg (sam,
262 GNUNET_MESSAGE_TYPE_ATS_SESSION_ALLOCATION);
263 sam->session_id = session->session_id;
264 sam->peer = *peer;
265 sam->bandwidth_in = bw_in;
266 sam->bandwidth_out = bw_out;
267 GNUNET_MQ_send (transport_client->mq,
268 env);
269}
270
271
272/**
273 * Convert @a properties to @a prop
274 *
275 * @param properties in NBO
276 * @param prop[out] in HBO
277 */
278static void
279prop_ntoh (const struct PropertiesNBO *properties,
280 struct GNUNET_ATS_Properties *prop)
281{
282 prop->delay = GNUNET_TIME_relative_ntoh (properties->delay);
283 prop->goodput_out = ntohl (properties->goodput_out);
284 prop->goodput_in = ntohl (properties->goodput_in);
285 prop->utilization_out = ntohl (properties->utilization_out);
286 prop->utilization_in = ntohl (properties->utilization_in);
287 prop->distance = ntohl (properties->distance);
288 prop->mtu = ntohl (properties->mtu);
289 prop->nt = (enum GNUNET_NetworkType) ntohl (properties->nt);
290 prop->cc = (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (
291 properties->cc);
292}
293
294
295/**
296 * We have received a `struct ExpressPreferenceMessage` from an application client.
297 *
298 * @param cls handle to the client
299 * @param msg the start message
300 */
301static void
302handle_suggest (void *cls,
303 const struct ExpressPreferenceMessage *msg)
304{
305 struct Client *c = cls;
306 struct ClientPreference *cp;
307
308 if (CT_NONE == c->type)
309 c->type = CT_APPLICATION;
310 if (CT_APPLICATION != c->type)
311 {
312 GNUNET_break (0);
313 GNUNET_SERVICE_client_drop (c->client);
314 return;
315 }
316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
317 "Client suggested we talk to %s with preference %d at rate %u\n",
318 GNUNET_i2s (&msg->peer),
319 (int) ntohl (msg->pk),
320 (int) ntohl (msg->bw.value__));
321 cp = GNUNET_new (struct ClientPreference);
322 cp->client = c;
323 cp->pref.peer = msg->peer;
324 cp->pref.bw = msg->bw;
325 cp->pref.pk = (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk);
326 cp->ph = plugin->preference_add (plugin->cls,
327 &cp->pref);
328 GNUNET_CONTAINER_DLL_insert (c->details.application.cp_head,
329 c->details.application.cp_tail,
330 cp);
331 GNUNET_SERVICE_client_continue (c->client);
332}
333
334
335/**
336 * We have received a `struct ExpressPreferenceMessage` from an application client.
337 *
338 * @param cls handle to the client
339 * @param msg the start message
340 */
341static void
342handle_suggest_cancel (void *cls,
343 const struct ExpressPreferenceMessage *msg)
344{
345 struct Client *c = cls;
346 struct ClientPreference *cp;
347
348 if (CT_NONE == c->type)
349 c->type = CT_APPLICATION;
350 if (CT_APPLICATION != c->type)
351 {
352 GNUNET_break (0);
353 GNUNET_SERVICE_client_drop (c->client);
354 return;
355 }
356 for (cp = c->details.application.cp_head;
357 NULL != cp;
358 cp = cp->next)
359 if ((cp->pref.pk == (enum GNUNET_MQ_PreferenceKind) ntohl (msg->pk)) &&
360 (cp->pref.bw.value__ == msg->bw.value__) &&
361 (0 == GNUNET_memcmp (&cp->pref.peer,
362 &msg->peer)))
363 break;
364 if (NULL == cp)
365 {
366 GNUNET_break (0);
367 GNUNET_SERVICE_client_drop (c->client);
368 return;
369 }
370 plugin->preference_del (plugin->cls,
371 cp->ph,
372 &cp->pref);
373 GNUNET_CONTAINER_DLL_remove (c->details.application.cp_head,
374 c->details.application.cp_tail,
375 cp);
376 GNUNET_free (cp);
377 GNUNET_SERVICE_client_continue (c->client);
378}
379
380
381/**
382 * Handle 'start' messages from transport clients.
383 *
384 * @param cls client that sent the request
385 * @param message the request message
386 */
387static void
388handle_start (void *cls,
389 const struct GNUNET_MessageHeader *hdr)
390{
391 struct Client *c = cls;
392
393 if (CT_NONE != c->type)
394 {
395 GNUNET_break (0);
396 GNUNET_SERVICE_client_drop (c->client);
397 return;
398 }
399 c->type = CT_TRANSPORT;
400 c->details.transport.sessions
401 = GNUNET_CONTAINER_multihashmap32_create (128);
402 if (NULL != transport_client)
403 {
404 GNUNET_SERVICE_client_drop (transport_client->client);
405 transport_client = NULL;
406 }
407 transport_client = c;
408 GNUNET_SERVICE_client_continue (c->client);
409}
410
411
412/**
413 * Check 'session_add' message is well-formed and comes from a
414 * transport client.
415 *
416 * @param cls client that sent the request
417 * @param message the request message
418 * @return #GNUNET_OK if @a message is well-formed
419 */
420static int
421check_session_add (void *cls,
422 const struct SessionAddMessage *message)
423{
424 struct Client *c = cls;
425
426 GNUNET_MQ_check_zero_termination (message);
427 if (CT_TRANSPORT != c->type)
428 {
429 GNUNET_break (0);
430 return GNUNET_SYSERR;
431 }
432 return GNUNET_OK;
433}
434
435
436/**
437 * Handle 'session add' messages from transport clients.
438 *
439 * @param cls client that sent the request
440 * @param message the request message
441 */
442static void
443handle_session_add (void *cls,
444 const struct SessionAddMessage *message)
445{
446 struct Client *c = cls;
447 const char *address = (const char *) &message[1];
448 struct GNUNET_ATS_Session *session;
449 int inbound_only = (GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY ==
450 ntohs (message->header.type));
451
452 session = GNUNET_CONTAINER_multihashmap32_get (c->details.transport.sessions,
453 message->session_id);
454 if (NULL != session)
455 {
456 GNUNET_break (0);
457 GNUNET_SERVICE_client_drop (c->client);
458 return;
459 }
460 session = GNUNET_new (struct GNUNET_ATS_Session);
461 session->data.session = session;
462 session->client = c;
463 session->session_id = message->session_id;
464 session->data.peer = message->peer;
465 prop_ntoh (&message->properties,
466 &session->data.prop);
467 session->data.inbound_only = inbound_only;
468 GNUNET_assert (GNUNET_YES ==
469 GNUNET_CONTAINER_multihashmap32_put (
470 c->details.transport.sessions,
471 message->session_id,
472 session,
473 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
474 session->sh = plugin->session_add (plugin->cls,
475 &session->data,
476 address);
477 GNUNET_assert (NULL != session->sh);
478 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
479 "Transport has new session %p to %s\n",
480 session,
481 GNUNET_i2s (&message->peer));
482 GNUNET_SERVICE_client_continue (c->client);
483}
484
485
486/**
487 * Handle 'session update' messages from transport clients.
488 *
489 * @param cls client that sent the request
490 * @param msg the request message
491 */
492static void
493handle_session_update (void *cls,
494 const struct SessionUpdateMessage *msg)
495{
496 struct Client *c = cls;
497 struct GNUNET_ATS_Session *session;
498
499 if (CT_TRANSPORT != c->type)
500 {
501 GNUNET_break (0);
502 GNUNET_SERVICE_client_drop (c->client);
503 return;
504 }
505 session = GNUNET_CONTAINER_multihashmap32_get (c->details.transport.sessions,
506 msg->session_id);
507 if (NULL == session)
508 {
509 GNUNET_break (0);
510 GNUNET_SERVICE_client_drop (c->client);
511 return;
512 }
513 prop_ntoh (&msg->properties,
514 &session->data.prop);
515 plugin->session_update (plugin->cls,
516 session->sh,
517 &session->data);
518 GNUNET_SERVICE_client_continue (c->client);
519}
520
521
522/**
523 * Handle 'session delete' messages from transport clients.
524 *
525 * @param cls client that sent the request
526 * @param message the request message
527 */
528static void
529handle_session_del (void *cls,
530 const struct SessionDelMessage *message)
531{
532 struct Client *c = cls;
533 struct GNUNET_ATS_Session *session;
534
535 if (CT_TRANSPORT != c->type)
536 {
537 GNUNET_break (0);
538 GNUNET_SERVICE_client_drop (c->client);
539 return;
540 }
541 session = GNUNET_CONTAINER_multihashmap32_get (c->details.transport.sessions,
542 message->session_id);
543 if (NULL == session)
544 {
545 GNUNET_break (0);
546 GNUNET_SERVICE_client_drop (c->client);
547 return;
548 }
549 GNUNET_assert (NULL != session->sh);
550 plugin->session_del (plugin->cls,
551 session->sh,
552 &session->data);
553 session->sh = NULL;
554 GNUNET_assert (GNUNET_YES ==
555 GNUNET_CONTAINER_multihashmap32_remove (
556 c->details.transport.sessions,
557 session->session_id,
558 session));
559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
560 "Transport lost session %p to %s\n",
561 session,
562 GNUNET_i2s (&session->data.peer));
563 GNUNET_free (session);
564 GNUNET_SERVICE_client_continue (c->client);
565}
566
567
568/**
569 * A client connected to us. Setup the local client
570 * record.
571 *
572 * @param cls unused
573 * @param client handle of the client
574 * @param mq message queue to talk to @a client
575 * @return @a client
576 */
577static void *
578client_connect_cb (void *cls,
579 struct GNUNET_SERVICE_Client *client,
580 struct GNUNET_MQ_Handle *mq)
581{
582 struct Client *c = GNUNET_new (struct Client);
583
584 c->client = client;
585 c->mq = mq;
586 return c;
587}
588
589
590/**
591 * Function called on each session to release associated state
592 * on transport disconnect.
593 *
594 * @param cls the `struct Client`
595 * @param key unused (session_id)
596 * @param value a `struct GNUNET_ATS_Session`
597 */
598static int
599free_session (void *cls,
600 uint32_t key,
601 void *value)
602{
603 struct Client *c = cls;
604 struct GNUNET_ATS_Session *session = value;
605
606 (void) key;
607 GNUNET_assert (c == session->client);
608 GNUNET_assert (NULL != session->sh);
609 plugin->session_del (plugin->cls,
610 session->sh,
611 &session->data);
612 session->sh = NULL;
613 GNUNET_free (session);
614 return GNUNET_OK;
615}
616
617
618/**
619 * A client disconnected from us. Tear down the local client
620 * record.
621 *
622 * @param cls unused
623 * @param client handle of the client
624 * @param app_ctx our `struct Client`
625 */
626static void
627client_disconnect_cb (void *cls,
628 struct GNUNET_SERVICE_Client *client,
629 void *app_ctx)
630{
631 struct Client *c = app_ctx;
632
633 (void) cls;
634 GNUNET_assert (c->client == client);
635 switch (c->type)
636 {
637 case CT_NONE:
638 break;
639
640 case CT_APPLICATION:
641 for (struct ClientPreference *cp = c->details.application.cp_head;
642 NULL != cp;
643 cp = c->details.application.cp_head)
644 {
645 plugin->preference_del (plugin->cls,
646 cp->ph,
647 &cp->pref);
648 GNUNET_CONTAINER_DLL_remove (c->details.application.cp_head,
649 c->details.application.cp_tail,
650 cp);
651 GNUNET_free (cp);
652 }
653 break;
654
655 case CT_TRANSPORT:
656 if (transport_client == c)
657 transport_client = NULL;
658 GNUNET_CONTAINER_multihashmap32_iterate (c->details.transport.sessions,
659 &free_session,
660 c);
661 GNUNET_CONTAINER_multihashmap32_destroy (c->details.transport.sessions);
662 break;
663 }
664 GNUNET_free (c);
665}
666
667
668/**
669 * Task run at the end during shutdown.
670 *
671 * @param cls unused
672 */
673static void
674final_cleanup (void *cls)
675{
676 (void) cls;
677 if (NULL != stats)
678 {
679 GNUNET_STATISTICS_destroy (stats,
680 GNUNET_NO);
681 stats = NULL;
682 }
683 if (NULL != plugin)
684 {
685 GNUNET_PLUGIN_unload (plugin_name,
686 plugin);
687 plugin = NULL;
688 }
689 if (NULL != plugin_name)
690 {
691 GNUNET_free (plugin_name);
692 plugin_name = NULL;
693 }
694}
695
696
697/**
698 * Task run during shutdown.
699 *
700 * @param cls unused
701 */
702static void
703cleanup_task (void *cls)
704{
705 (void) cls;
706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
707 "ATS shutdown initiated\n");
708 GNUNET_SCHEDULER_add_now (&final_cleanup,
709 NULL);
710}
711
712
713/**
714 * Process template requests.
715 *
716 * @param cls closure
717 * @param cfg configuration to use
718 * @param service the initialized service
719 */
720static void
721run (void *cls,
722 const struct GNUNET_CONFIGURATION_Handle *cfg,
723 struct GNUNET_SERVICE_Handle *service)
724{
725 static struct GNUNET_ATS_PluginEnvironment env;
726 char *solver;
727
728 stats = GNUNET_STATISTICS_create ("ats",
729 cfg);
730 if (GNUNET_SYSERR ==
731 GNUNET_CONFIGURATION_get_value_string (cfg,
732 "ats",
733 "SOLVER",
734 &solver))
735 {
736 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
737 "No ATS solver configured, using 'simple' approach\n");
738 solver = GNUNET_strdup ("simple");
739 }
740 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
741 NULL);
742 env.cls = NULL;
743 env.cfg = cfg;
744 env.stats = stats;
745 env.suggest_cb = &suggest_cb;
746 env.allocate_cb = &allocate_cb;
747 GNUNET_asprintf (&plugin_name,
748 "libgnunet_plugin_ats2_%s",
749 solver);
750 GNUNET_free (solver);
751 if (NULL == (plugin = GNUNET_PLUGIN_load (plugin_name,
752 &env)))
753 {
754 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
755 _ ("Failed to initialize solver `%s'!\n"),
756 plugin_name);
757 GNUNET_SCHEDULER_shutdown ();
758 return;
759 }
760}
761
762
763/**
764 * Define "main" method using service macro.
765 */
766GNUNET_SERVICE_MAIN
767 ("ats",
768 GNUNET_SERVICE_OPTION_NONE,
769 &run,
770 &client_connect_cb,
771 &client_disconnect_cb,
772 NULL,
773 GNUNET_MQ_hd_fixed_size (suggest,
774 GNUNET_MESSAGE_TYPE_ATS_SUGGEST,
775 struct ExpressPreferenceMessage,
776 NULL),
777 GNUNET_MQ_hd_fixed_size (suggest_cancel,
778 GNUNET_MESSAGE_TYPE_ATS_SUGGEST_CANCEL,
779 struct ExpressPreferenceMessage,
780 NULL),
781 GNUNET_MQ_hd_fixed_size (start,
782 GNUNET_MESSAGE_TYPE_ATS_START,
783 struct GNUNET_MessageHeader,
784 NULL),
785 GNUNET_MQ_hd_var_size (session_add,
786 GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD,
787 struct SessionAddMessage,
788 NULL),
789 GNUNET_MQ_hd_var_size (session_add,
790 GNUNET_MESSAGE_TYPE_ATS_SESSION_ADD_INBOUND_ONLY,
791 struct SessionAddMessage,
792 NULL),
793 GNUNET_MQ_hd_fixed_size (session_update,
794 GNUNET_MESSAGE_TYPE_ATS_SESSION_UPDATE,
795 struct SessionUpdateMessage,
796 NULL),
797 GNUNET_MQ_hd_fixed_size (session_del,
798 GNUNET_MESSAGE_TYPE_ATS_SESSION_DEL,
799 struct SessionDelMessage,
800 NULL),
801 GNUNET_MQ_handler_end ());
802
803
804/* end of gnunet-service-ats.c */
diff --git a/src/ats/perf_ats_solver_mlp.conf b/src/ats/perf_ats_solver_mlp.conf
deleted file mode 100644
index e69de29bb..000000000
--- a/src/ats/perf_ats_solver_mlp.conf
+++ /dev/null
diff --git a/src/ats/perf_ats_solver_ril.conf b/src/ats/perf_ats_solver_ril.conf
deleted file mode 100644
index e69de29bb..000000000
--- a/src/ats/perf_ats_solver_ril.conf
+++ /dev/null
diff --git a/src/ats/plugin_ats2_common.c b/src/ats/plugin_ats2_common.c
deleted file mode 100644
index da20a342c..000000000
--- a/src/ats/plugin_ats2_common.c
+++ /dev/null
@@ -1,99 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2015, 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/plugin_ats2_common.c
22 * @brief ATS solver helper functions to be inlined
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26
27/**
28 * Default bandwidth assigned to a network: 64 KB/s
29 */
30#define DEFAULT_BANDWIDTH 65536
31
32
33/**
34 * Parse @a cfg for @a quota as specified for @a direction of
35 * network type @a nts.
36 *
37 * @param cfg configuration to parse
38 * @param nts network type string to get quota for
39 * @param direction direction to get quota for ("IN" or "OUT")
40 * @param quota[out] set to quota, #DEFAULT_BANDWIDTH if @a cfg does not say anything useful
41 */
42static void
43get_quota (const struct GNUNET_CONFIGURATION_Handle *cfg,
44 const char *nts,
45 const char *direction,
46 unsigned long long *quota)
47{
48 char *quota_str;
49 char *quota_s;
50 int res;
51
52 GNUNET_asprintf (&quota_s,
53 "%s_QUOTA_%s",
54 nts,
55 direction);
56 if (GNUNET_OK !=
57 GNUNET_CONFIGURATION_get_value_string (cfg,
58 "ATS",
59 quota_s,
60 &quota_str))
61 {
62 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
63 "ATS",
64 quota_s);
65 GNUNET_free (quota_s);
66 return;
67 }
68 GNUNET_free (quota_s);
69 res = GNUNET_NO;
70 if (0 == strcmp (quota_str,
71 "unlimited"))
72 {
73 *quota = ULONG_MAX;
74 res = GNUNET_YES;
75 }
76 if ((GNUNET_NO == res) &&
77 (GNUNET_OK ==
78 GNUNET_STRINGS_fancy_size_to_bytes (quota_str,
79 quota)))
80 res = GNUNET_YES;
81 if ((GNUNET_NO == res) &&
82 (1 ==
83 sscanf (quota_str,
84 "%llu",
85 quota)))
86 res = GNUNET_YES;
87 if (GNUNET_NO == res)
88 {
89 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
90 _ (
91 "Could not load %s quota for network `%s': `%s', assigning default bandwidth %llu\n"),
92 direction,
93 nts,
94 quota_str,
95 (unsigned long long) DEFAULT_BANDWIDTH);
96 *quota = DEFAULT_BANDWIDTH;
97 }
98 GNUNET_free (quota_str);
99}
diff --git a/src/ats/plugin_ats2_simple.c b/src/ats/plugin_ats2_simple.c
deleted file mode 100644
index 3062b6019..000000000
--- a/src/ats/plugin_ats2_simple.c
+++ /dev/null
@@ -1,1087 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2015, 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file ats/plugin_ats2_simple.c
22 * @brief ATS simple solver
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - needs testing
28 */
29#include "platform.h"
30#include "gnunet_ats_plugin_new.h"
31#include "gnunet_hello_lib.h"
32#include "gnunet_peerstore_service.h"
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "ats-simple", __VA_ARGS__)
35
36
37/**
38 * Base frequency at which we suggest addresses to transport.
39 * Multiplied by the square of the number of active connections
40 * (and randomized) to calculate the actual frequency at which
41 * we will suggest addresses to the transport. Furthermore, each
42 * address is also bounded by an exponential back-off.
43 */
44#define SUGGEST_FREQ GNUNET_TIME_UNIT_SECONDS
45
46/**
47 * What is the minimum bandwidth we always try to allocate for
48 * any session that is up? (May still be scaled down lower if
49 * the number of sessions is so high that the total bandwidth
50 * is insufficient to allow for this value to be granted.)
51 */
52#define MIN_BANDWIDTH_PER_SESSION 1024
53
54
55/**
56 * A handle for the proportional solver
57 */
58struct SimpleHandle;
59
60
61/**
62 * Information about preferences and sessions we track
63 * per peer.
64 */
65struct Peer;
66
67
68/**
69 * Entry in list of addresses we could try per peer.
70 */
71struct Hello
72{
73 /**
74 * Kept in a DLL.
75 */
76 struct Hello *next;
77
78 /**
79 * Kept in a DLL.
80 */
81 struct Hello *prev;
82
83 /**
84 * Peer this hello belongs to.
85 */
86 struct Peer *peer;
87
88 /**
89 * The address we could try.
90 */
91 const char *address;
92
93 /**
94 * Is a session with this address already up?
95 * If not, set to NULL.
96 */
97 struct GNUNET_ATS_SessionHandle *sh;
98
99 /**
100 * When does the HELLO expire?
101 */
102 struct GNUNET_TIME_Absolute expiration;
103
104 /**
105 * When did we try it last?
106 */
107 struct GNUNET_TIME_Absolute last_attempt;
108
109 /**
110 * Current exponential backoff value.
111 */
112 struct GNUNET_TIME_Relative backoff;
113
114 /**
115 * Type of the network for this HELLO.
116 */
117 enum GNUNET_NetworkType nt;
118};
119
120
121/**
122 * Internal representation of a session by the plugin.
123 * (If desired, plugin may just use NULL.)
124 */
125struct GNUNET_ATS_SessionHandle
126{
127 /**
128 * Kept in DLL per peer.
129 */
130 struct GNUNET_ATS_SessionHandle *next;
131
132 /**
133 * Kept in DLL per peer.
134 */
135 struct GNUNET_ATS_SessionHandle *prev;
136
137 /**
138 * The session in the main ATS service.
139 */
140 struct GNUNET_ATS_Session *session;
141
142 /**
143 * Current performance data for this @e session
144 */
145 const struct GNUNET_ATS_SessionData *data;
146
147 /**
148 * Hello matching this session, or NULL for none.
149 */
150 struct Hello *hello;
151
152 /**
153 * Peer this session is for.
154 */
155 struct Peer *peer;
156
157 /**
158 * Address used by this session (largely for debugging).
159 */
160 const char *address;
161
162 /**
163 * When did we last update transport about the allocation?
164 * Used to dampen the frequency of updates.
165 */
166 struct GNUNET_TIME_Absolute last_allocation;
167
168 /**
169 * Last BW-in allocation given to the transport service.
170 */
171 struct GNUNET_BANDWIDTH_Value32NBO bw_in;
172
173 /**
174 * Last BW-out allocation given to the transport service.
175 */
176 struct GNUNET_BANDWIDTH_Value32NBO bw_out;
177
178 /**
179 * New BW-in allocation given to the transport service.
180 */
181 uint64_t target_in;
182
183 /**
184 * New BW-out allocation given to the transport service.
185 */
186 uint64_t target_out;
187};
188
189
190/**
191 * Information about preferences and sessions we track
192 * per peer.
193 */
194struct Peer
195{
196 /**
197 * Kept in DLL per peer.
198 */
199 struct GNUNET_ATS_SessionHandle *sh_head;
200
201 /**
202 * Kept in DLL per peer.
203 */
204 struct GNUNET_ATS_SessionHandle *sh_tail;
205
206 /**
207 * Kept in a DLL.
208 */
209 struct Hello *h_head;
210
211 /**
212 * Kept in a DLL.
213 */
214 struct Hello *h_tail;
215
216 /**
217 * The handle for the proportional solver
218 */
219 struct SimpleHandle *h;
220
221 /**
222 * Watch context where we are currently looking for HELLOs for
223 * this peer.
224 */
225 struct GNUNET_PEERSTORE_WatchContext *wc;
226
227 /**
228 * Task used to try again to suggest an address for this peer.
229 */
230 struct GNUNET_SCHEDULER_Task *task;
231
232 /**
233 * Which peer is this for?
234 */
235 struct GNUNET_PeerIdentity pid;
236
237 /**
238 * When did we last suggest an address to connect to for this peer?
239 */
240 struct GNUNET_TIME_Absolute last_suggestion;
241
242 /**
243 * Array where we sum up the bandwidth requests received indexed
244 * by preference kind (see `enum GNUNET_MQ_PreferenceKind`)
245 */
246 uint64_t bw_by_pk[GNUNET_MQ_PREFERENCE_COUNT];
247};
248
249
250/**
251 * Representation of a network (to be expanded...)
252 */
253struct Network
254{
255 /**
256 * Total inbound quota
257 */
258 unsigned long long total_quota_in;
259
260 /**
261 * Total outbound quota
262 */
263 unsigned long long total_quota_out;
264
265 /**
266 * ATS network type
267 */
268 enum GNUNET_NetworkType type;
269};
270
271
272/**
273 * A handle for the proportional solver
274 */
275struct SimpleHandle
276{
277 /**
278 * Our execution environment.
279 */
280 struct GNUNET_ATS_PluginEnvironment *env;
281
282 /**
283 * Information we track for each peer.
284 */
285 struct GNUNET_CONTAINER_MultiPeerMap *peers;
286
287 /**
288 * Handle to the peerstore service.
289 */
290 struct GNUNET_PEERSTORE_Handle *ps;
291
292 /**
293 * Array where we sum up the bandwidth requests received indexed
294 * by preference kind (see `enum GNUNET_MQ_PreferenceKind`) (sums
295 * over all peers).
296 */
297 uint64_t bw_by_pk[GNUNET_MQ_PREFERENCE_COUNT];
298
299 /**
300 * Information we track per network type (quotas).
301 */
302 struct Network networks[GNUNET_NT_COUNT];
303};
304
305
306/**
307 * Lookup peer in the peers map.
308 *
309 * @param h handle to look up in
310 * @param pid peer identity to look up by
311 * @return NULL for not found
312 */
313struct Peer *
314lookup_peer (struct SimpleHandle *h, const struct GNUNET_PeerIdentity *pid)
315{
316 return GNUNET_CONTAINER_multipeermap_get (h->peers, pid);
317}
318
319
320/**
321 * Check if there is _any_ interesting information left we
322 * store about the peer in @a p.
323 *
324 * @param p peer to test if we can drop the data structure
325 * @return #GNUNET_YES if no information is left in @a p
326 */
327static int
328peer_test_dead (struct Peer *p)
329{
330 for (enum GNUNET_MQ_PreferenceKind pk = 0; pk < GNUNET_MQ_PREFERENCE_COUNT;
331 pk++)
332 if (0 != p->bw_by_pk[pk])
333 return GNUNET_NO;
334 if (NULL != p->sh_head)
335 return GNUNET_NO;
336 return GNUNET_YES;
337}
338
339
340/**
341 * Contact the transport service and suggest to it to
342 * try connecting to the address of @a hello. Updates
343 * backoff and timestamp values in the @a hello.
344 *
345 * @param hello[in,out] address suggestion to make
346 */
347static void
348suggest_hello (struct Hello *hello)
349{
350 struct Peer *p = hello->peer;
351 struct SimpleHandle *h = p->h;
352
353 p->last_suggestion = hello->last_attempt = GNUNET_TIME_absolute_get ();
354 hello->backoff =
355 GNUNET_TIME_randomized_backoff (hello->backoff,
356 GNUNET_TIME_absolute_get_remaining (
357 hello->expiration));
358 h->env->suggest_cb (h->env->cls, &p->pid, hello->address);
359}
360
361
362/**
363 * Consider suggesting a HELLO (without a session) to transport.
364 * We look at how many active sessions we have for the peer, and
365 * if there are many, reduce the frequency of trying new addresses.
366 * Also, for each address we consider when we last tried it, and
367 * its exponential backoff if the attempt failed. Note that it
368 * is possible that this function is called when no suggestion
369 * is to be made.
370 *
371 * In this case, we only calculate the time until we make the next
372 * suggestion.
373 *
374 * @param cls a `struct Peer`
375 */
376static void
377suggest_start_cb (void *cls)
378{
379 struct Peer *p = cls;
380 struct GNUNET_TIME_Relative delay = GNUNET_TIME_UNIT_ZERO;
381 struct Hello *hello = NULL;
382 struct GNUNET_TIME_Absolute hpt = GNUNET_TIME_UNIT_FOREVER_ABS;
383 struct GNUNET_TIME_Relative xdelay;
384 struct GNUNET_TIME_Absolute xnext;
385 unsigned int num_sessions = 0;
386 uint32_t sq;
387
388 /* count number of active sessions */
389 for (struct GNUNET_ATS_SessionHandle *sh = p->sh_head; NULL != sh;
390 sh = sh->next)
391 num_sessions++;
392 /* calculate square of number of sessions */
393 num_sessions++; /* start with 1, even if we have zero sessions */
394 if (num_sessions < UINT16_MAX)
395 sq = num_sessions * (uint32_t) num_sessions;
396 else
397 sq = UINT32_MAX;
398 xdelay =
399 GNUNET_TIME_randomized_backoff (GNUNET_TIME_relative_multiply (SUGGEST_FREQ,
400 sq),
401 GNUNET_TIME_UNIT_FOREVER_REL);
402 xnext = GNUNET_TIME_relative_to_absolute (xdelay);
403
404 p->task = NULL;
405 while (0 == delay.rel_value_us)
406 {
407 struct Hello *next;
408 struct GNUNET_TIME_Absolute xmax;
409
410 if (NULL != hello)
411 {
412 /* We went through the loop already once and found
413 a HELLO that is due *now*, so make a suggestion! */
414 GNUNET_break (NULL == hello->sh);
415 suggest_hello (hello);
416 hello = NULL;
417 hpt = GNUNET_TIME_UNIT_FOREVER_ABS;
418 }
419 for (struct Hello *pos = p->h_head; NULL != pos; pos = next)
420 {
421 struct GNUNET_TIME_Absolute pt;
422
423 next = pos->next;
424 if (NULL != pos->sh)
425 continue;
426 if (0 ==
427 GNUNET_TIME_absolute_get_remaining (pos->expiration).rel_value_us)
428 {
429 /* expired, remove! */
430 GNUNET_CONTAINER_DLL_remove (p->h_head, p->h_tail, pos);
431 GNUNET_free (pos);
432 continue;
433 }
434 pt = GNUNET_TIME_absolute_add (pos->last_attempt, pos->backoff);
435 if ((NULL == hello) || (pt.abs_value_us < hpt.abs_value_us))
436 {
437 hello = pos;
438 hpt = pt;
439 }
440 }
441 if (NULL == hello)
442 return; /* no HELLOs that could still be tried */
443
444 /* hpt is now the *earliest* possible time for any HELLO
445 but we might not want to go for as early as possible for
446 this peer. So the actual time is the max of the earliest
447 HELLO and the 'xnext' */
448 xmax = GNUNET_TIME_absolute_max (hpt, xnext);
449 delay = GNUNET_TIME_absolute_get_remaining (xmax);
450 }
451 p->task = GNUNET_SCHEDULER_add_delayed (delay, &suggest_start_cb, p);
452}
453
454
455/**
456 * Function called by PEERSTORE for each matching record.
457 *
458 * @param cls closure with a `struct Peer`
459 * @param record peerstore record information
460 * @param emsg error message, or NULL if no errors
461 */
462static void
463watch_cb (void *cls,
464 const struct GNUNET_PEERSTORE_Record *record,
465 const char *emsg)
466{
467 struct Peer *p = cls;
468 char *addr;
469 size_t alen;
470 enum GNUNET_NetworkType nt;
471 struct GNUNET_TIME_Absolute expiration;
472 struct Hello *hello;
473
474 if (0 != GNUNET_memcmp (&p->pid, &record->peer))
475 {
476 GNUNET_break (0);
477 return;
478 }
479 if (0 != strcmp (record->key, GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY))
480 {
481 GNUNET_break (0);
482 return;
483 }
484 addr = GNUNET_HELLO_extract_address (record->value,
485 record->value_size,
486 &p->pid,
487 &nt,
488 &expiration);
489 if (NULL == addr)
490 return; /* invalid hello, bad signature, other problem */
491 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
492 {
493 /* expired, ignore */
494 GNUNET_free (addr);
495 return;
496 }
497 /* check if addr is already known */
498 for (struct Hello *he = p->h_head; NULL != he; he = he->next)
499 {
500 if (0 != strcmp (he->address, addr))
501 continue;
502 if (he->expiration.abs_value_us < expiration.abs_value_us)
503 {
504 he->expiration = expiration;
505 he->nt = nt;
506 }
507 GNUNET_free (addr);
508 return;
509 }
510 /* create new HELLO */
511 alen = strlen (addr) + 1;
512 hello = GNUNET_malloc (sizeof(struct Hello) + alen);
513 hello->address = (const char *) &hello[1];
514 hello->expiration = expiration;
515 hello->nt = nt;
516 hello->peer = p;
517 memcpy (&hello[1], addr, alen);
518 GNUNET_CONTAINER_DLL_insert (p->h_head, p->h_tail, hello);
519 /* check if sh for this HELLO already exists */
520 for (struct GNUNET_ATS_SessionHandle *sh = p->sh_head; NULL != sh;
521 sh = sh->next)
522 {
523 if ((NULL == sh->address) || (0 != strcmp (sh->address, addr)))
524 continue;
525 GNUNET_assert (NULL == sh->hello);
526 sh->hello = hello;
527 hello->sh = sh;
528 break;
529 }
530 GNUNET_free (addr);
531 if (NULL == p->task)
532 p->task = GNUNET_SCHEDULER_add_now (&suggest_start_cb, p);
533}
534
535
536/**
537 * Find or add peer if necessary.
538 *
539 * @param h our plugin handle
540 * @param pid the peer identity to add/look for
541 * @return a peer handle
542 */
543static struct Peer *
544peer_add (struct SimpleHandle *h, const struct GNUNET_PeerIdentity *pid)
545{
546 struct Peer *p = lookup_peer (h, pid);
547
548 if (NULL != p)
549 return p;
550 p = GNUNET_new (struct Peer);
551 p->h = h;
552 p->pid = *pid;
553 p->wc = GNUNET_PEERSTORE_watch (h->ps,
554 "transport",
555 &p->pid,
556 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
557 &watch_cb,
558 p);
559 GNUNET_assert (GNUNET_YES ==
560 GNUNET_CONTAINER_multipeermap_put (
561 h->peers,
562 &p->pid,
563 p,
564 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
565
566 return p;
567}
568
569
570/**
571 * Free the entry (and associated tasks) of peer @a p.
572 * Note that @a p must be dead already (see #peer_test_dead()).
573 *
574 * @param p the peer to free
575 */
576static void
577peer_free (struct Peer *p)
578{
579 struct SimpleHandle *h = p->h;
580 struct Hello *hello;
581
582 GNUNET_assert (NULL == p->sh_head);
583 while (NULL != (hello = p->h_head))
584 {
585 GNUNET_CONTAINER_DLL_remove (p->h_head, p->h_tail, hello);
586 GNUNET_assert (NULL == hello->sh);
587 GNUNET_free (hello);
588 }
589 if (NULL != p->task)
590 {
591 GNUNET_SCHEDULER_cancel (p->task);
592 p->task = NULL;
593 }
594 if (NULL != p->wc)
595 {
596 GNUNET_PEERSTORE_watch_cancel (p->wc);
597 p->wc = NULL;
598 }
599 GNUNET_assert (GNUNET_YES ==
600 GNUNET_CONTAINER_multipeermap_remove (h->peers, &p->pid, p));
601 GNUNET_free (p);
602}
603
604
605/**
606 * Check if the new allocation for @a sh is significantly different
607 * from the last one, and if so, tell transport.
608 *
609 * @param sh session handle to consider updating transport for
610 */
611static void
612consider_notify_transport (struct GNUNET_ATS_SessionHandle *sh)
613{
614 struct Peer *peer = sh->peer;
615 struct SimpleHandle *h = peer->h;
616 enum GNUNET_NetworkType nt = sh->data->prop.nt;
617 struct GNUNET_TIME_Relative delay;
618 uint64_t sig_in;
619 uint64_t sig_out;
620 int64_t delta_in;
621 int64_t delta_out;
622
623 delay = GNUNET_TIME_absolute_get_duration (sh->last_allocation);
624 /* A significant change is more than 10% of the quota,
625 which is given in bytes/second */
626 sig_in = h->networks[nt].total_quota_in * (delay.rel_value_us / 1000LL)
627 / 1000LL / 10;
628 sig_out = h->networks[nt].total_quota_out * (delay.rel_value_us / 1000LL)
629 / 1000LL / 10;
630 delta_in = ((int64_t) ntohl (sh->bw_in.value__)) - ((int64_t) sh->target_in);
631 delta_out = ((int64_t) ntohl (sh->bw_in.value__)) - ((int64_t) sh->target_in);
632 /* we want the absolute values */
633 if (delta_in < 0)
634 delta_in = -delta_in;
635 if (INT64_MIN == delta_in)
636 delta_in = INT64_MAX; /* Handle corner case: INT_MIN == - INT_MIN */
637 if (delta_out < 0)
638 delta_out = -delta_out;
639 if (INT64_MIN == delta_out)
640 delta_out = INT64_MAX; /* Handle corner case: INT_MIN == - INT_MIN */
641 if ((sig_in > delta_in) && (sig_out > delta_out))
642 return; /* insignificant change */
643 /* change is significant, tell transport! */
644 if (sh->target_in > UINT32_MAX)
645 sh->target_in = UINT32_MAX;
646 sh->bw_in.value__ = htonl ((uint32_t) sh->target_in);
647 if (sh->target_out > UINT32_MAX)
648 sh->target_out = UINT32_MAX;
649 sh->bw_out.value__ = htonl ((uint32_t) sh->target_out);
650 sh->last_allocation = GNUNET_TIME_absolute_get ();
651 h->env->allocate_cb (h->env->cls,
652 sh->session,
653 &peer->pid,
654 sh->bw_in,
655 sh->bw_out);
656}
657
658
659/**
660 * Closure for #update_counters and #update_allocation.
661 */
662struct Counters
663{
664 /**
665 * Plugin's state.
666 */
667 struct SimpleHandle *h;
668
669 /**
670 * Bandwidth that applications would prefer to allocate in this
671 * network type. We initially add all requested allocations to the
672 * respective network type where the given preference is best
673 * satisfied. Later we may rebalance.
674 */
675 uint64_t bw_out_by_nt[GNUNET_NT_COUNT];
676
677 /**
678 * Current bandwidth utilization for this network type. We simply
679 * add the current goodput up (with some fairness considerations).
680 */
681 uint64_t bw_in_by_nt[GNUNET_NT_COUNT];
682
683 /**
684 * By how much do we have to scale (up or down) our expectations
685 * for outbound bandwidth?
686 */
687 double scale_out[GNUNET_NT_COUNT];
688
689 /**
690 * By how much do we have to scale (up or down) our expectations
691 * for inbound bandwidth?
692 */
693 double scale_in[GNUNET_NT_COUNT];
694};
695
696
697/**
698 * Function used to iterate over all peers and collect
699 * counter data.
700 *
701 * @param cls a `struct Counters *`
702 * @param pid identity of the peer we process, unused
703 * @param value a `struct Peer *`
704 * @return #GNUNET_YES (continue to iterate)
705 */
706static int
707update_counters (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
708{
709 struct Counters *c = cls;
710 struct Peer *peer = value;
711 struct GNUNET_ATS_SessionHandle *best[GNUNET_MQ_PREFERENCE_COUNT];
712
713 (void) pid;
714 if (NULL == peer->sh_head)
715 return GNUNET_YES; /* no available session, cannot allocate bandwidth */
716 memset (best, 0, sizeof(best));
717 for (struct GNUNET_ATS_SessionHandle *sh = peer->sh_head; NULL != sh;
718 sh = sh->next)
719 {
720 enum GNUNET_NetworkType nt = sh->data->prop.nt;
721
722 sh->target_out = MIN_BANDWIDTH_PER_SESSION;
723 c->bw_out_by_nt[nt] += MIN_BANDWIDTH_PER_SESSION;
724 c->bw_in_by_nt[nt] +=
725 GNUNET_MAX (MIN_BANDWIDTH_PER_SESSION, sh->data->prop.goodput_in);
726 for (enum GNUNET_MQ_PreferenceKind pk = 0; pk < GNUNET_MQ_PREFERENCE_COUNT;
727 pk++)
728 {
729 /* General rule: always prefer smaller distance if possible,
730 otherwise decide by pk: */
731 switch (pk)
732 {
733 case GNUNET_MQ_PREFERENCE_NONE:
734 break;
735
736 case GNUNET_MQ_PREFERENCE_BANDWIDTH:
737 /* For bandwidth, we compare the sum of transmitted bytes and
738 confirmed transmitted bytes, so confirmed data counts twice */
739 if ((NULL == best[pk]) ||
740 (sh->data->prop.distance < best[pk]->data->prop.distance) ||
741 (sh->data->prop.utilization_out + sh->data->prop.goodput_out >
742 best[pk]->data->prop.utilization_out
743 + best[pk]->data->prop.goodput_out))
744 best[pk] = sh;
745 /* If both are equal (i.e. usually this happens if there is a zero), use
746 latency as a yardstick */
747 if ((sh->data->prop.utilization_out + sh->data->prop.goodput_out ==
748 best[pk]->data->prop.utilization_out
749 + best[pk]->data->prop.goodput_out) &&
750 (sh->data->prop.distance == best[pk]->data->prop.distance) &&
751 (sh->data->prop.delay.rel_value_us <
752 best[pk]->data->prop.delay.rel_value_us))
753 best[pk] = sh;
754 break;
755
756 case GNUNET_MQ_PREFERENCE_LATENCY:
757 if ((NULL == best[pk]) ||
758 (sh->data->prop.distance < best[pk]->data->prop.distance) ||
759 ((sh->data->prop.distance == best[pk]->data->prop.distance) &&
760 (sh->data->prop.delay.rel_value_us <
761 best[pk]->data->prop.delay.rel_value_us)))
762 best[pk] = sh;
763 break;
764
765 case GNUNET_MQ_PREFERENCE_RELIABILITY:
766 /* For reliability, we consider the ratio of goodput to utilization
767 (but use multiplicative formultations to avoid division by zero) */
768 if ((NULL == best[pk]) || (1ULL * sh->data->prop.goodput_out
769 * best[pk]->data->prop.utilization_out >
770 1ULL * sh->data->prop.utilization_out
771 * best[pk]->data->prop.goodput_out))
772 best[pk] = sh;
773 /* If both are equal (i.e. usually this happens if there is a zero), use
774 latency as a yardstick */
775 if ((1ULL * sh->data->prop.goodput_out
776 * best[pk]->data->prop.utilization_out ==
777 1ULL * sh->data->prop.utilization_out
778 * best[pk]->data->prop.goodput_out) &&
779 (sh->data->prop.distance == best[pk]->data->prop.distance) &&
780 (sh->data->prop.delay.rel_value_us <
781 best[pk]->data->prop.delay.rel_value_us))
782 best[pk] = sh;
783 break;
784 }
785 }
786 }
787 /* for first round, assign target bandwidth simply to sum of
788 requested bandwidth */
789 for (enum GNUNET_MQ_PreferenceKind pk =
790 1 /* skip GNUNET_MQ_PREFERENCE_NONE */;
791 pk < GNUNET_MQ_PREFERENCE_COUNT;
792 pk++)
793 {
794 const struct GNUNET_ATS_SessionData *data = best[pk]->data;
795 enum GNUNET_NetworkType nt;
796
797 GNUNET_assert (NULL != data);
798 nt = data->prop.nt;
799 best[pk]->target_out =
800 GNUNET_MIN (peer->bw_by_pk[pk], MIN_BANDWIDTH_PER_SESSION);
801 c->bw_out_by_nt[nt] +=
802 (uint64_t) (best[pk]->target_out - MIN_BANDWIDTH_PER_SESSION);
803 }
804 return GNUNET_YES;
805}
806
807
808/**
809 * Function used to iterate over all peers and collect
810 * counter data.
811 *
812 * @param cls a `struct Counters *`
813 * @param pid identity of the peer we process, unused
814 * @param value a `struct Peer *`
815 * @return #GNUNET_YES (continue to iterate)
816 */
817static int
818update_allocation (void *cls,
819 const struct GNUNET_PeerIdentity *pid,
820 void *value)
821{
822 struct Counters *c = cls;
823 struct Peer *peer = value;
824
825 (void) pid;
826 for (struct GNUNET_ATS_SessionHandle *sh = peer->sh_head; NULL != sh;
827 sh = sh->next)
828 {
829 enum GNUNET_NetworkType nt = sh->data->prop.nt;
830
831 sh->target_out = (uint64_t) (c->scale_out[nt] * sh->target_out);
832 sh->target_in = (uint64_t) (c->scale_in[nt] * sh->target_in);
833 consider_notify_transport (sh);
834 }
835 return GNUNET_YES;
836}
837
838
839/**
840 * The world changed, recalculate our allocations.
841 */
842static void
843update (struct SimpleHandle *h)
844{
845 struct Counters cnt = { .h = h };
846
847 GNUNET_CONTAINER_multipeermap_iterate (h->peers, &update_counters, &cnt);
848 /* calculate how badly the missmatch between requested
849 allocations and available bandwidth is per network type */
850 for (enum GNUNET_NetworkType nt = 0; nt < GNUNET_NT_COUNT; nt++)
851 {
852 cnt.scale_out[nt] =
853 1.0 * cnt.bw_out_by_nt[nt] / h->networks[nt].total_quota_out;
854 cnt.scale_in[nt] =
855 1.0 * cnt.bw_in_by_nt[nt] / h->networks[nt].total_quota_in;
856 }
857 /* recalculate allocations, considering scaling factor, and
858 update transport if the change is significant */
859 GNUNET_CONTAINER_multipeermap_iterate (h->peers, &update_allocation, &cnt);
860}
861
862
863/**
864 * The plugin should begin to respect a new preference.
865 *
866 * @param cls the closure
867 * @param pref the preference to add
868 * @return plugin's internal representation, or NULL
869 */
870static struct GNUNET_ATS_PreferenceHandle *
871simple_preference_add (void *cls, const struct GNUNET_ATS_Preference *pref)
872{
873 struct SimpleHandle *h = cls;
874 struct Peer *p = peer_add (h, &pref->peer);
875
876 GNUNET_assert (pref->pk < GNUNET_MQ_PREFERENCE_COUNT);
877 p->bw_by_pk[pref->pk] += ntohl (pref->bw.value__);
878 h->bw_by_pk[pref->pk] += ntohl (pref->bw.value__);
879 update (h);
880 return NULL;
881}
882
883
884/**
885 * The plugin should end respecting a preference.
886 *
887 * @param cls the closure
888 * @param ph whatever @e preference_add returned
889 * @param pref the preference to delete
890 * @return plugin's internal representation, or NULL
891 */
892static void
893simple_preference_del (void *cls,
894 struct GNUNET_ATS_PreferenceHandle *ph,
895 const struct GNUNET_ATS_Preference *pref)
896{
897 struct SimpleHandle *h = cls;
898 struct Peer *p = lookup_peer (h, &pref->peer);
899
900 GNUNET_assert (NULL != p);
901 GNUNET_assert (pref->pk < GNUNET_MQ_PREFERENCE_COUNT);
902 p->bw_by_pk[pref->pk] -= ntohl (pref->bw.value__);
903 h->bw_by_pk[pref->pk] -= ntohl (pref->bw.value__);
904 if ((0 == p->bw_by_pk[pref->pk]) && (GNUNET_YES == peer_test_dead (p)))
905 peer_free (p);
906 update (h);
907}
908
909
910/**
911 * Transport established a new session with performance
912 * characteristics given in @a data.
913 *
914 * @param cls closure
915 * @param data performance characteristics of @a sh
916 * @param address address information (for debugging)
917 * @return handle by which the plugin will identify this session
918 */
919static struct GNUNET_ATS_SessionHandle *
920simple_session_add (void *cls,
921 const struct GNUNET_ATS_SessionData *data,
922 const char *address)
923{
924 struct SimpleHandle *h = cls;
925 struct Peer *p = peer_add (h, &data->peer);
926 struct Hello *hello;
927 size_t alen;
928 struct GNUNET_ATS_SessionHandle *sh;
929
930 /* setup session handle */
931 GNUNET_assert (NULL != data);
932 if (NULL == address)
933 alen = 0;
934 else
935 alen = strlen (address) + 1;
936 sh = GNUNET_malloc (sizeof(struct GNUNET_ATS_SessionHandle) + alen);
937 sh->peer = p;
938 sh->session = data->session;
939 sh->data = data;
940 if (NULL == address)
941 {
942 sh->address = NULL;
943 }
944 else
945 {
946 memcpy (&sh[1], address, alen);
947 sh->address = (const char *) &sh[1];
948 }
949 GNUNET_CONTAINER_DLL_insert (p->sh_head, p->sh_tail, sh);
950 if (NULL != address)
951 {
952 /* match HELLO */
953 hello = p->h_head;
954 while ((NULL != hello) && (0 != strcmp (address, hello->address)))
955 hello = hello->next;
956 if (NULL != hello)
957 {
958 hello->sh = sh;
959 hello->backoff = GNUNET_TIME_UNIT_ZERO;
960 sh->hello = hello;
961 }
962 }
963 update (h);
964 return sh;
965}
966
967
968/**
969 * @a data changed for a given @a sh, solver should consider
970 * the updated performance characteristics.
971 *
972 * @param cls closure
973 * @param sh session this is about
974 * @param data performance characteristics of @a sh
975 */
976static void
977simple_session_update (void *cls,
978 struct GNUNET_ATS_SessionHandle *sh,
979 const struct GNUNET_ATS_SessionData *data)
980{
981 struct SimpleHandle *h = cls;
982
983 GNUNET_assert (NULL != data);
984 sh->data = data; /* this statement should not really do anything... */
985 update (h);
986}
987
988
989/**
990 * A session went away. Solver should update accordingly.
991 *
992 * @param cls closure
993 * @param sh session this is about
994 * @param data (last) performance characteristics of @a sh
995 */
996static void
997simple_session_del (void *cls,
998 struct GNUNET_ATS_SessionHandle *sh,
999 const struct GNUNET_ATS_SessionData *data)
1000{
1001 struct SimpleHandle *h = cls;
1002 struct Peer *p = sh->peer;
1003 struct Hello *hello = sh->hello;
1004
1005 /* clean up sh */
1006 GNUNET_CONTAINER_DLL_remove (p->sh_head, p->sh_tail, sh);
1007 if (NULL != hello)
1008 {
1009 GNUNET_assert (sh == hello->sh);
1010 hello->sh = NULL;
1011 /* session went down, if necessary restart suggesting
1012 addresses */
1013 if (NULL == p->task)
1014 p->task = GNUNET_SCHEDULER_add_now (&suggest_start_cb, p);
1015 }
1016 GNUNET_free (sh);
1017 /* del peer if otherwise dead */
1018 if ((NULL == p->sh_head) && (GNUNET_YES == peer_test_dead (p)))
1019 peer_free (p);
1020 update (h);
1021}
1022
1023
1024#include "plugin_ats2_common.c"
1025
1026
1027/**
1028 * Function invoked when the plugin is loaded.
1029 *
1030 * @param[in,out] cls the `struct GNUNET_ATS_PluginEnvironment *` to use;
1031 * modified to return the API functions (ugh).
1032 * @return the `struct SimpleHandle` to pass as a closure
1033 */
1034void *
1035libgnunet_plugin_ats2_simple_init (void *cls)
1036{
1037 static struct GNUNET_ATS_SolverFunctions sf;
1038 struct GNUNET_ATS_PluginEnvironment *env = cls;
1039 struct SimpleHandle *s;
1040
1041 s = GNUNET_new (struct SimpleHandle);
1042 s->env = env;
1043 s->peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
1044 s->ps = GNUNET_PEERSTORE_connect (env->cfg);
1045 sf.cls = s;
1046 sf.preference_add = &simple_preference_add;
1047 sf.preference_del = &simple_preference_del;
1048 sf.session_add = &simple_session_add;
1049 sf.session_update = &simple_session_update;
1050 sf.session_del = &simple_session_del;
1051 for (enum GNUNET_NetworkType nt = 0; nt < GNUNET_NT_COUNT; nt++)
1052 {
1053 const char *name = GNUNET_NT_to_string (nt);
1054
1055 if (NULL == name)
1056 {
1057 GNUNET_break (0);
1058 break;
1059 }
1060 get_quota (env->cfg, name, "IN", &s->networks[nt].total_quota_in);
1061 get_quota (env->cfg, name, "OUT", &s->networks[nt].total_quota_out);
1062 s->networks[nt].type = nt;
1063 }
1064 return &sf;
1065}
1066
1067
1068/**
1069 * Function used to unload the plugin.
1070 *
1071 * @param cls return value from #libgnunet_plugin_ats_proportional_init()
1072 */
1073void *
1074libgnunet_plugin_ats2_simple_done (void *cls)
1075{
1076 struct GNUNET_ATS_SolverFunctions *sf = cls;
1077 struct SimpleHandle *s = sf->cls;
1078
1079 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (s->peers));
1080 GNUNET_CONTAINER_multipeermap_destroy (s->peers);
1081 GNUNET_PEERSTORE_disconnect (s->ps, GNUNET_NO);
1082 GNUNET_free (s);
1083 return NULL;
1084}
1085
1086
1087/* end of plugin_ats2_simple.c */
diff --git a/src/ats/plugin_ats_mlp.c b/src/ats/plugin_ats_mlp.c
deleted file mode 100644
index 6ab823b1e..000000000
--- a/src/ats/plugin_ats_mlp.c
+++ /dev/null
@@ -1,2924 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/plugin_ats_mlp.c
23 * @brief ats mlp problem solver
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_ats_service.h"
30#include "gnunet_ats_plugin.h"
31#include "gnunet-service-ats_addresses.h"
32#include "gnunet_statistics_service.h"
33#include <float.h>
34#include <glpk.h>
35
36
37#define BIG_M_VALUE (UINT32_MAX) / 10
38#define BIG_M_STRING "unlimited"
39
40#define MLP_AVERAGING_QUEUE_LENGTH 3
41
42#define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply ( \
43 GNUNET_TIME_UNIT_SECONDS, 10)
44#define MLP_MAX_ITERATIONS 4096
45
46#define MLP_DEFAULT_D 1.0
47#define MLP_DEFAULT_R 1.0
48#define MLP_DEFAULT_U 1.0
49#define MLP_DEFAULT_QUALITY 1.0
50#define MLP_DEFAULT_MIN_CONNECTIONS 4
51#define MLP_DEFAULT_PEER_PREFERENCE 1.0
52
53#define MLP_NaN -1
54#define MLP_UNDEFINED 0
55#define GLP_YES 1.0
56#define GLP_NO 0.0
57
58enum MLP_Output_Format
59{
60 MLP_MPS,
61 MLP_CPLEX,
62 MLP_GLPK
63};
64
65
66enum QualityMetrics
67{
68 RQ_QUALITY_METRIC_DELAY = 0,
69 RQ_QUALITY_METRIC_DISTANCE = 1,
70 RQ_QUALITY_METRIC_COUNT = 2
71};
72
73
74static const char *
75print_quality_type (enum QualityMetrics qm)
76{
77 switch (qm)
78 {
79 case RQ_QUALITY_METRIC_DELAY:
80 return "delay";
81
82 case RQ_QUALITY_METRIC_DISTANCE:
83 return "distance";
84
85 default:
86 GNUNET_break (0);
87 return NULL;
88 }
89}
90
91
92struct MLP_Solution
93{
94 int lp_res;
95 int lp_presolv;
96 int mip_res;
97 int mip_presolv;
98
99 double lp_objective_value;
100 double mlp_objective_value;
101 double mlp_gap;
102 double lp_mlp_gap;
103
104 int p_elements;
105 int p_cols;
106 int p_rows;
107
108 int n_peers;
109 int n_addresses;
110};
111
112struct ATS_Peer
113{
114 struct GNUNET_PeerIdentity id;
115
116 /* Was this peer already added to the current problem? */
117 int processed;
118
119 /* constraint 2: 1 address per peer*/
120 unsigned int r_c2;
121
122 /* constraint 9: relativity */
123 unsigned int r_c9;
124
125 /* Legacy preference value */
126 double f;
127};
128
129struct MLP_Problem
130{
131 /**
132 * GLPK (MLP) problem object
133 */
134 glp_prob *prob;
135
136 /* Number of addresses in problem */
137 unsigned int num_addresses;
138 /* Number of peers in problem */
139 unsigned int num_peers;
140 /* Number of elements in problem matrix */
141 unsigned int num_elements;
142
143 /* Row index constraint 2: */
144 unsigned int r_c2;
145 /* Row index constraint 4: minimum connections */
146 unsigned int r_c4;
147 /* Row index constraint 6: maximize diversity */
148 unsigned int r_c6;
149 /* Row index constraint 8: utilization*/
150 unsigned int r_c8;
151 /* Row index constraint 9: relativity*/
152 unsigned int r_c9;
153 /* Row indices quality metrics */
154 int r_q[RQ_QUALITY_METRIC_COUNT];
155 /* Row indices ATS network quotas */
156 int r_quota[GNUNET_NT_COUNT];
157
158 /* Column index Diversity (D) column */
159 int c_d;
160 /* Column index Utilization (U) column */
161 int c_u;
162 /* Column index Proportionality (R) column */
163 int c_r;
164 /* Column index quality metrics */
165 int c_q[RQ_QUALITY_METRIC_COUNT];
166
167 /* Problem matrix */
168 /* Current index */
169 unsigned int ci;
170 /* Row index array */
171 int *ia;
172 /* Column index array */
173 int *ja;
174 /* Column index value */
175 double *ar;
176};
177
178struct MLP_Variables
179{
180 /* Big M value for bandwidth capping */
181 double BIG_M;
182
183 /* MIP Gap */
184 double mip_gap;
185
186 /* LP MIP Gap */
187 double lp_mip_gap;
188
189 /* Number of quality metrics @deprecated, use RQ_QUALITY_METRIC_COUNT */
190 int m_q;
191
192 /* Number of quality metrics */
193 int m_rc;
194
195 /* Quality metric coefficients*/
196 double co_Q[RQ_QUALITY_METRIC_COUNT];
197
198 /* Ressource costs coefficients*/
199 double co_RC[RQ_QUALITY_METRIC_COUNT];
200
201 /* Diversity coefficient */
202 double co_D;
203
204 /* Utility coefficient */
205 double co_U;
206
207 /* Relativity coefficient */
208 double co_R;
209
210 /* Minimum bandwidth assigned to an address */
211 unsigned int b_min;
212
213 /* Minimum number of addresses with bandwidth assigned */
214 unsigned int n_min;
215
216 /* Quotas */
217 /* Array mapping array index to ATS network */
218 int quota_index[GNUNET_NT_COUNT];
219 /* Outbound quotas */
220 unsigned long long quota_out[GNUNET_NT_COUNT];
221 /* Inbound quotas */
222
223 unsigned long long quota_in[GNUNET_NT_COUNT];
224
225 /* ATS ressource costs
226 * array with GNUNET_ATS_QualityPropertiesCount elements
227 * contains mapping to GNUNET_ATS_Property
228 * */
229 int rc[RQ_QUALITY_METRIC_COUNT];
230};
231
232/**
233 * MLP Handle
234 */
235struct GAS_MLP_Handle
236{
237 struct GNUNET_ATS_PluginEnvironment *env;
238
239 /**
240 * Exclude peer from next result propagation
241 */
242 const struct GNUNET_PeerIdentity *exclude_peer;
243
244 /**
245 * Encapsulation for the MLP problem
246 */
247 struct MLP_Problem p;
248
249 /**
250 * Encapsulation for the MLP problem variables
251 */
252 struct MLP_Variables pv;
253
254 /**
255 * Encapsulation for the MLP solution
256 */
257 struct MLP_Solution ps;
258
259 /**
260 * Bulk lock
261 */
262 int stat_bulk_lock;
263
264 /**
265 * Number of changes while solver was locked
266 */
267 int stat_bulk_requests;
268
269 /**
270 * GLPK LP control parameter
271 */
272 glp_smcp control_param_lp;
273
274 /**
275 * GLPK LP control parameter
276 */
277 glp_iocp control_param_mlp;
278
279 /**
280 * Peers with pending address requests
281 */
282 struct GNUNET_CONTAINER_MultiPeerMap *requested_peers;
283
284 /**
285 * Was the problem updated since last solution
286 */
287 int stat_mlp_prob_updated;
288
289 /**
290 * Has the problem size changed since last solution
291 */
292 int stat_mlp_prob_changed;
293
294 /**
295 * Solve the problem automatically when updates occur?
296 * Default: GNUNET_YES
297 * Can be disabled for test and measurements
298 */
299 int opt_mlp_auto_solve;
300
301 /**
302 * Write all MILP problems to a MPS file
303 */
304 int opt_dump_problem_all;
305
306 /**
307 * Write all MILP problem solutions to a file
308 */
309 int opt_dump_solution_all;
310
311 /**
312 * Write MILP problems to a MPS file when solver fails
313 */
314 int opt_dump_problem_on_fail;
315
316 /**
317 * Write MILP problem solutions to a file when solver fails
318 */
319 int opt_dump_solution_on_fail;
320
321 /**
322 * solve feasibility only
323 */
324 int opt_dbg_feasibility_only;
325
326 /**
327 * solve autoscale the problem
328 */
329 int opt_dbg_autoscale_problem;
330
331 /**
332 * use the intopt presolver instead of simplex
333 */
334 int opt_dbg_intopt_presolver;
335
336 /**
337 * Print GLPK output
338 */
339 int opt_dbg_glpk_verbose;
340
341 /**
342 * solve autoscale the problem
343 */
344 int opt_dbg_optimize_relativity;
345
346 /**
347 * solve autoscale the problem
348 */
349 int opt_dbg_optimize_diversity;
350
351 /**
352 * solve autoscale the problem
353 */
354 int opt_dbg_optimize_quality;
355
356 /**
357 * solve autoscale the problem
358 */
359 int opt_dbg_optimize_utility;
360
361
362 /**
363 * Output format
364 */
365 enum MLP_Output_Format opt_log_format;
366};
367
368/**
369 * Address specific MLP information
370 */
371struct MLP_information
372{
373 /**
374 * Bandwidth assigned outbound
375 */
376 uint32_t b_out;
377
378 /**
379 * Bandwidth assigned inbound
380 */
381 uint32_t b_in;
382
383 /**
384 * Address selected
385 */
386 int n;
387
388 /**
389 * bandwidth column index
390 */
391 signed int c_b;
392
393 /**
394 * address usage column
395 */
396 signed int c_n;
397
398 /* row indexes */
399
400 /**
401 * constraint 1: bandwidth capping
402 */
403 unsigned int r_c1;
404
405 /**
406 * constraint 3: minimum bandwidth
407 */
408 unsigned int r_c3;
409};
410
411
412
413/**
414 *
415 * NOTE: Do not modify this documentation. This documentation is based on
416 * gnunet.org:/vcs/fsnsg/ats-paper.git/tech-doku/ats-tech-guide.tex
417 * use build_txt.sh to generate plaintext output
418 *
419 * The MLP solver (mlp) tries to finds an optimal bandwidth assignmentby
420 * optimizing an mixed integer programming problem. The MLP solver uses a
421 * number of constraints to find the best adddress for a peer and an optimal
422 * bandwidth assignment. mlp uses the GNU Linear Programming Kit to solve the
423 * MLP problem.
424 *
425 * We defined a constraint system to find an optimal bandwidth assignment.
426 * This constraint system uses as an input data addresses, bandwidth quotas,
427 * preferences and quality values. This constraint system is stored in an
428 * matrix based equotation system.
429 *
430 * 5 Using GLPK
431 *
432 * A (M)LP problem consists of a target function to optimizes, constraints
433 * and rows and columns. FIXME GLP uses three arrays to index the matrix: two
434 * integer arrays storing the row and column indices in the matrix and an
435 * float array to store the coeeficient.
436 *
437 * To solve the problem we first find an initial solution for the LP problem
438 * using the LP solver and then find an MLP solution based on this solution
439 * using the MLP solver.
440 *
441 * Solving (M)LP problems has the property that finding an initial solution
442 * for the LP problem is computationally expensive and finding the MLP
443 * solution is cheaper. This is especially interesting an existing LP
444 * solution can be reused if only coefficients in the matrix have changed
445 * (addresses updated). Only when the problem size changes (addresses added
446 * or deleted) a new LP solution has to be found.
447 *
448 * Intended usage
449 * The mlp solver solves the bandwidth assignment problem only on demand when
450 * an address suggestion is requested. When an address is requested mlp the
451 * solves the mlp problem and if the active address or the bandwidth assigned
452 * changes it calls the callback to addresses. The mlp solver gets notified
453 * about new addresses (adding sessions), removed addresses (address
454 * deletions) and address updates. To benefit from the mlp properties
455 * mentioned in section 5 the solver rembers if since the last solution
456 * addresses were added or deleted (problem size changed, problem has to be
457 * rebuild and solved from sratch) or if addresses were updated and the
458 * existing solution can be reused.
459 *
460 * 5.1 Input data
461 *
462 * The quotas for each network segment are passed by addresses. MLP can be
463 * adapted using configuration settings and uses the following parameters:
464 * * MLP_MAX_DURATION:
465 * Maximum duration for a MLP solution procees (default: 3 sec.)
466 * * MLP_MAX_ITERATIONS:
467 * Maximum number of iterations for a MLP solution process (default:
468 * 1024)
469 * * MLP_MIN_CONNECTIONS:
470 * Minimum number of desired connections (default: 4)
471 * * MLP_MIN_BANDWIDTH:
472 * Minimum amount of bandwidth assigned to an address (default: 1024)
473 * * MLP_COEFFICIENT_D:
474 * Diversity coefficient (default: 1.0)
475 * * MLP_COEFFICIENT_R:
476 * Relativity coefficient (default: 1.0)
477 * * MLP_COEFFICIENT_U:
478 * Utilization coefficient (default: 1.0)
479 * * MLP_COEFFICIENT_D:
480 * Diversity coefficient (default: 1.0)
481 * * MLP_COEFFICIENT_QUALITY_DELAY:
482 * Quality delay coefficient (default: 1.0)
483 * * MLP_COEFFICIENT_QUALITY_DISTANCE:
484 * Quality distance coefficient (default: 1.0)
485 * * MLP_COEFFICIENT_QUALITY_DISTANCE:
486 * Quality distance coefficient (default: 1.0)
487 * * MLP_COEFFICIENT_QUALITY_DISTANCE:
488 * Quality distance coefficient (default: 1.0)
489 * * MLP_COEFFICIENT_QUALITY_DISTANCE:
490 * Quality distance coefficient (default: 1.0)
491 *
492 * 5.2 Data structures used
493 *
494 * mlp has for each known peer a struct ATS_Peer containing information about
495 * a specific peer. The address field solver_information contains information
496 * about the mlp properties of this address.
497 *
498 * 5.3 Initializing
499 *
500 * During initialization mlp initializes the GLPK libray used to solve the
501 * MLP problem: it initializes the glpk environment and creates an initial LP
502 * problem. Next it loads the configuration values from the configuration or
503 * uses the default values configured in -addresses_mlp.h. The quotas used
504 * are given by addresses but may have to be adjusted. mlp uses a upper limit
505 * for the bandwidth assigned called BIG M and a minimum amount of bandwidth
506 * an address gets assigned as well as a minium desired number of
507 * connections. If the configured quota is bigger than BIG M, it is reduced
508 * to BIG M. If the configured quota is smaller than MLP_MIN_CONNECTIONS
509 * *MLP_MIN_BANDWIDTH it is increased to this value.
510 *
511 * 5.4 Shutdown
512
513 */
514
515#define LOG(kind, ...) GNUNET_log_from (kind, "ats-mlp", __VA_ARGS__)
516
517/**
518 * Print debug output for mlp problem creation
519 */
520#define DEBUG_MLP_PROBLEM_CREATION GNUNET_NO
521
522
523/**
524 * Intercept GLPK terminal output
525 * @param info the mlp handle
526 * @param s the string to print
527 * @return 0: glpk prints output on terminal, 0 != surpress output
528 */
529static int
530mlp_term_hook (void *info, const char *s)
531{
532 struct GAS_MLP_Handle *mlp = info;
533
534 if (mlp->opt_dbg_glpk_verbose)
535 LOG (GNUNET_ERROR_TYPE_ERROR, "%s", s);
536 return 1;
537}
538
539
540/**
541 * Reset peers for next problem creation
542 *
543 * @param cls not used
544 * @param key the key
545 * @param value ATS_Peer
546 * @return #GNUNET_OK
547 */
548static int
549reset_peers (void *cls,
550 const struct GNUNET_PeerIdentity *key,
551 void *value)
552{
553 struct ATS_Peer *peer = value;
554
555 peer->processed = GNUNET_NO;
556 return GNUNET_OK;
557}
558
559/**
560 * Delete the MLP problem and free the constrain matrix
561 *
562 * @param mlp the MLP handle
563 */
564static void
565mlp_delete_problem (struct GAS_MLP_Handle *mlp)
566{
567 int c;
568
569 if (mlp == NULL)
570 return;
571 if (mlp->p.prob != NULL)
572 {
573 glp_delete_prob (mlp->p.prob);
574 mlp->p.prob = NULL;
575 }
576
577 /* delete row index */
578 if (mlp->p.ia != NULL)
579 {
580 GNUNET_free (mlp->p.ia);
581 mlp->p.ia = NULL;
582 }
583
584 /* delete column index */
585 if (mlp->p.ja != NULL)
586 {
587 GNUNET_free (mlp->p.ja);
588 mlp->p.ja = NULL;
589 }
590
591 /* delete coefficients */
592 if (mlp->p.ar != NULL)
593 {
594 GNUNET_free (mlp->p.ar);
595 mlp->p.ar = NULL;
596 }
597 mlp->p.ci = 0;
598 mlp->p.prob = NULL;
599
600 mlp->p.c_d = MLP_UNDEFINED;
601 mlp->p.c_r = MLP_UNDEFINED;
602 mlp->p.r_c2 = MLP_UNDEFINED;
603 mlp->p.r_c4 = MLP_UNDEFINED;
604 mlp->p.r_c6 = MLP_UNDEFINED;
605 mlp->p.r_c9 = MLP_UNDEFINED;
606 for (c = 0; c < RQ_QUALITY_METRIC_COUNT; c++)
607 mlp->p.r_q[c] = MLP_UNDEFINED;
608 for (c = 0; c < GNUNET_NT_COUNT; c++)
609 mlp->p.r_quota[c] = MLP_UNDEFINED;
610 mlp->p.ci = MLP_UNDEFINED;
611
612
613 GNUNET_CONTAINER_multipeermap_iterate (mlp->requested_peers,
614 &reset_peers, NULL);
615}
616
617
618/**
619 * Translate glpk status error codes to text
620 * @param retcode return code
621 * @return string with result
622 */
623static const char *
624mlp_status_to_string (int retcode)
625{
626 switch (retcode)
627 {
628 case GLP_UNDEF:
629 return "solution is undefined";
630
631 case GLP_FEAS:
632 return "solution is feasible";
633
634 case GLP_INFEAS:
635 return "solution is infeasible";
636
637 case GLP_NOFEAS:
638 return "no feasible solution exists";
639
640 case GLP_OPT:
641 return "solution is optimal";
642
643 case GLP_UNBND:
644 return "solution is unbounded";
645
646 default:
647 GNUNET_break (0);
648 return "unknown error";
649 }
650}
651
652
653/**
654 * Translate glpk solver error codes to text
655 * @param retcode return code
656 * @return string with result
657 */
658static const char *
659mlp_solve_to_string (int retcode)
660{
661 switch (retcode)
662 {
663 case 0:
664 return "ok";
665
666 case GLP_EBADB:
667 return "invalid basis";
668
669 case GLP_ESING:
670 return "singular matrix";
671
672 case GLP_ECOND:
673 return "ill-conditioned matrix";
674
675 case GLP_EBOUND:
676 return "invalid bounds";
677
678 case GLP_EFAIL:
679 return "solver failed";
680
681 case GLP_EOBJLL:
682 return "objective lower limit reached";
683
684 case GLP_EOBJUL:
685 return "objective upper limit reached";
686
687 case GLP_EITLIM:
688 return "iteration limit exceeded";
689
690 case GLP_ETMLIM:
691 return "time limit exceeded";
692
693 case GLP_ENOPFS:
694 return "no primal feasible solution";
695
696 case GLP_ENODFS:
697 return "no dual feasible solution";
698
699 case GLP_EROOT:
700 return "root LP optimum not provided";
701
702 case GLP_ESTOP:
703 return "search terminated by application";
704
705 case GLP_EMIPGAP:
706 return "relative mip gap tolerance reached";
707
708 case GLP_ENOFEAS:
709 return "no dual feasible solution";
710
711 case GLP_ENOCVG:
712 return "no convergence";
713
714 case GLP_EINSTAB:
715 return "numerical instability";
716
717 case GLP_EDATA:
718 return "invalid data";
719
720 case GLP_ERANGE:
721 return "result out of range";
722
723 default:
724 GNUNET_break (0);
725 return "unknown error";
726 }
727}
728
729
730struct CountContext
731{
732 const struct GNUNET_CONTAINER_MultiPeerMap *map;
733 int result;
734};
735
736static int
737mlp_create_problem_count_addresses_it (void *cls,
738 const struct GNUNET_PeerIdentity *key,
739 void *value)
740{
741 struct CountContext *cctx = cls;
742
743 /* Check if we have to add this peer due to a pending request */
744 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (cctx->map, key))
745 cctx->result++;
746 return GNUNET_OK;
747}
748
749
750static int
751mlp_create_problem_count_addresses (const struct
752 GNUNET_CONTAINER_MultiPeerMap *
753 requested_peers,
754 const struct
755 GNUNET_CONTAINER_MultiPeerMap *addresses)
756{
757 struct CountContext cctx;
758
759 cctx.map = requested_peers;
760 cctx.result = 0;
761 GNUNET_CONTAINER_multipeermap_iterate (addresses,
762 &mlp_create_problem_count_addresses_it,
763 &cctx);
764 return cctx.result;
765}
766
767
768static int
769mlp_create_problem_count_peers_it (void *cls,
770 const struct GNUNET_PeerIdentity *key,
771 void *value)
772{
773 struct CountContext *cctx = cls;
774
775 /* Check if we have to addresses for the requested peer */
776 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (cctx->map, key))
777 cctx->result++;
778 return GNUNET_OK;
779}
780
781
782static int
783mlp_create_problem_count_peers (const struct
784 GNUNET_CONTAINER_MultiPeerMap *requested_peers,
785 const struct
786 GNUNET_CONTAINER_MultiPeerMap *addresses)
787{
788 struct CountContext cctx;
789
790 cctx.map = addresses;
791 cctx.result = 0;
792 GNUNET_CONTAINER_multipeermap_iterate (requested_peers,
793 &mlp_create_problem_count_peers_it,
794 &cctx);
795 return cctx.result;
796}
797
798
799/**
800 * Updates an existing value in the matrix
801 *
802 * Extract the row, updates the value and updates the row in the problem
803 *
804 * @param p the mlp problem
805 * @param row the row to create the value in
806 * @param col the column to create the value in
807 * @param val the value to set
808 * @param line calling line for debbuging
809 * @return GNUNET_YES value changed, GNUNET_NO value did not change, GNUNET_SYSERR
810 * on error
811 */
812static int
813mlp_create_problem_update_value (struct MLP_Problem *p,
814 int row, int col, double val,
815 int line)
816{
817 int c_cols;
818 int c_elems;
819 int c1;
820 int res;
821 int found;
822 double *val_array;
823 int *ind_array;
824
825 GNUNET_assert (NULL != p->prob);
826
827 /* Get number of columns and prepare data structure */
828 c_cols = glp_get_num_cols (p->prob);
829 if (0 >= c_cols)
830 return GNUNET_SYSERR;
831
832 val_array = GNUNET_malloc ((c_cols + 1) * sizeof(double));
833 GNUNET_assert (NULL != val_array);
834 ind_array = GNUNET_malloc ((c_cols + 1) * sizeof(int));
835 GNUNET_assert (NULL != ind_array);
836 /* Extract the row */
837
838 /* Update the value */
839 c_elems = glp_get_mat_row (p->prob, row, ind_array, val_array);
840 found = GNUNET_NO;
841 for (c1 = 1; c1 < (c_elems + 1); c1++)
842 {
843 if (ind_array[c1] == col)
844 {
845 found = GNUNET_YES;
846 break;
847 }
848 }
849 if (GNUNET_NO == found)
850 {
851 ind_array[c_elems + 1] = col;
852 val_array[c_elems + 1] = val;
853 LOG (GNUNET_ERROR_TYPE_DEBUG, "[P] Setting value in [%s : %s] to `%.2f'\n",
854 glp_get_row_name (p->prob, row), glp_get_col_name (p->prob, col),
855 val);
856 glp_set_mat_row (p->prob, row, c_elems + 1, ind_array, val_array);
857 GNUNET_free (ind_array);
858 GNUNET_free (val_array);
859 return GNUNET_YES;
860 }
861 else
862 {
863 /* Update value */
864 LOG (GNUNET_ERROR_TYPE_DEBUG,
865 "[P] Updating value in [%s : %s] from `%.2f' to `%.2f'\n",
866 glp_get_row_name (p->prob, row), glp_get_col_name (p->prob, col),
867 val_array[c1], val);
868 if (val != val_array[c1])
869 res = GNUNET_YES;
870 else
871 res = GNUNET_NO;
872 val_array[c1] = val;
873 /* Update the row in the matrix */
874 glp_set_mat_row (p->prob, row, c_elems, ind_array, val_array);
875 }
876
877 GNUNET_free (ind_array);
878 GNUNET_free (val_array);
879 return res;
880}
881
882/**
883 * Creates a new value in the matrix
884 *
885 * Sets the row and column index in the problem array and increments the
886 * position field
887 *
888 * @param p the mlp problem
889 * @param row the row to create the value in
890 * @param col the column to create the value in
891 * @param val the value to set
892 * @param line calling line for debbuging
893 */
894static void
895mlp_create_problem_set_value (struct MLP_Problem *p,
896 int row, int col, double val,
897 int line)
898{
899 if ((p->ci) >= p->num_elements)
900 {
901 LOG (GNUNET_ERROR_TYPE_DEBUG,
902 "[P]: line %u: Request for index %u bigger than array size of %u\n",
903 line, p->ci + 1, p->num_elements);
904 GNUNET_break (0);
905 return;
906 }
907 if ((0 == row) || (0 == col))
908 {
909 GNUNET_break (0);
910 LOG (GNUNET_ERROR_TYPE_ERROR,
911 "[P]: Invalid call from line %u: row = %u, col = %u\n",
912 line, row, col);
913 }
914 p->ia[p->ci] = row;
915 p->ja[p->ci] = col;
916 p->ar[p->ci] = val;
917#if DEBUG_MLP_PROBLEM_CREATION
918 LOG (GNUNET_ERROR_TYPE_DEBUG,
919 "[P]: line %u: Set value [%u,%u] in index %u == %.2f\n",
920 line, p->ia[p->ci], p->ja[p->ci], p->ci, p->ar[p->ci]);
921#endif
922 p->ci++;
923}
924
925static int
926mlp_create_problem_create_column (struct MLP_Problem *p, char *name,
927 unsigned int type, unsigned int bound, double
928 lb, double ub,
929 double coef)
930{
931 int col = glp_add_cols (p->prob, 1);
932
933 glp_set_col_name (p->prob, col, name);
934 glp_set_col_bnds (p->prob, col, bound, lb, ub);
935 glp_set_col_kind (p->prob, col, type);
936 glp_set_obj_coef (p->prob, col, coef);
937#if DEBUG_MLP_PROBLEM_CREATION
938 LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added column [%u] `%s': %.2f\n",
939 col, name, coef);
940#endif
941 return col;
942}
943
944static int
945mlp_create_problem_create_constraint (struct MLP_Problem *p, char *name,
946 unsigned int bound, double lb, double ub)
947{
948 char *op;
949 int row = glp_add_rows (p->prob, 1);
950
951 /* set row name */
952 glp_set_row_name (p->prob, row, name);
953 /* set row bounds: <= 0 */
954 glp_set_row_bnds (p->prob, row, bound, lb, ub);
955 switch (bound)
956 {
957 case GLP_UP:
958 GNUNET_asprintf (&op, "-inf <= x <= %.2f", ub);
959 break;
960
961 case GLP_DB:
962 GNUNET_asprintf (&op, "%.2f <= x <= %.2f", lb, ub);
963 break;
964
965 case GLP_FX:
966 GNUNET_asprintf (&op, "%.2f == x == %.2f", lb, ub);
967 break;
968
969 case GLP_LO:
970 GNUNET_asprintf (&op, "%.2f <= x <= inf", lb);
971 break;
972
973 default:
974 GNUNET_asprintf (&op, "ERROR");
975 break;
976 }
977#if DEBUG_MLP_PROBLEM_CREATION
978 LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added row [%u] `%s': %s\n",
979 row, name, op);
980#endif
981 GNUNET_free (op);
982 return row;
983}
984
985/**
986 * Create the
987 * - address columns b and n
988 * - address dependent constraint rows c1, c3
989 * - peer dependent rows c2 and c9
990 * - Set address dependent entries in problem matrix as well
991 */
992static int
993mlp_create_problem_add_address_information (void *cls,
994 const struct
995 GNUNET_PeerIdentity *key,
996 void *value)
997{
998 struct GAS_MLP_Handle *mlp = cls;
999 struct MLP_Problem *p = &mlp->p;
1000 struct ATS_Address *address = value;
1001 struct ATS_Peer *peer;
1002 struct MLP_information *mlpi;
1003 char *name;
1004 double cur_bigm;
1005 uint32_t addr_net;
1006 uint32_t addr_net_index;
1007 unsigned long long max_quota;
1008 int c;
1009
1010 /* Check if we have to add this peer due to a pending request */
1011 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (mlp->requested_peers,
1012 key))
1013 return GNUNET_OK;
1014
1015 mlpi = address->solver_information;
1016 if (NULL == mlpi)
1017 {
1018 fprintf (stderr, "%s %p\n", GNUNET_i2s (&address->peer), address);
1019 GNUNET_break (0);
1020 return GNUNET_OK;
1021 }
1022
1023 addr_net = address->properties.scope;
1024 for (addr_net_index = 0; addr_net_index < GNUNET_NT_COUNT; addr_net_index++)
1025 {
1026 if (mlp->pv.quota_index[addr_net_index] == addr_net)
1027 break;
1028 }
1029
1030 if (addr_net_index >= GNUNET_NT_COUNT)
1031 {
1032 GNUNET_break (0);
1033 return GNUNET_OK;
1034 }
1035
1036 max_quota = 0;
1037 for (c = 0; c < GNUNET_NT_COUNT; c++)
1038 {
1039 if (mlp->pv.quota_out[c] > max_quota)
1040 max_quota = mlp->pv.quota_out[c];
1041 if (mlp->pv.quota_in[c] > max_quota)
1042 max_quota = mlp->pv.quota_in[c];
1043 }
1044 if (max_quota > mlp->pv.BIG_M)
1045 cur_bigm = (double) mlp->pv.BIG_M;
1046 else
1047 cur_bigm = max_quota;
1048
1049
1050 /* Get peer */
1051 peer = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, key);
1052 GNUNET_assert (NULL != peer);
1053 if (peer->processed == GNUNET_NO)
1054 {
1055 /* Add peer dependent constraints */
1056 /* Add c2) One address active per peer */
1057 GNUNET_asprintf (&name, "c2_%s", GNUNET_i2s (&address->peer));
1058 peer->r_c2 = mlp_create_problem_create_constraint (p, name, GLP_FX, 1.0,
1059 1.0);
1060 GNUNET_free (name);
1061 if (GNUNET_NO == mlp->opt_dbg_feasibility_only)
1062 {
1063 if (GNUNET_YES == mlp->opt_dbg_optimize_relativity)
1064 {
1065 /* Add c9) Relativity */
1066 GNUNET_asprintf (&name, "c9_%s", GNUNET_i2s (&address->peer));
1067 peer->r_c9 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0,
1068 0.0);
1069 GNUNET_free (name);
1070 /* c9) set coefficient */
1071 mlp_create_problem_set_value (p, peer->r_c9, p->c_r, -peer->f,
1072 __LINE__);
1073 }
1074 }
1075 peer->processed = GNUNET_YES;
1076 }
1077
1078 /* Reset addresses' solver information */
1079 mlpi->c_b = 0;
1080 mlpi->c_n = 0;
1081 mlpi->n = 0;
1082 mlpi->r_c1 = 0;
1083 mlpi->r_c3 = 0;
1084
1085 /* Add bandwidth column */
1086 GNUNET_asprintf (&name, "b_%s_%s_%p", GNUNET_i2s (&address->peer),
1087 address->plugin, address);
1088 if (GNUNET_NO == mlp->opt_dbg_feasibility_only)
1089 {
1090 mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0,
1091 0.0, 0.0);
1092 }
1093 else
1094 {
1095 /* Maximize for bandwidth assignment in feasibility testing */
1096 mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0,
1097 0.0, 1.0);
1098 }
1099 GNUNET_free (name);
1100
1101 /* Add address active column */
1102 GNUNET_asprintf (&name, "n_%s_%s_%p", GNUNET_i2s (&address->peer),
1103 address->plugin, address);
1104 mlpi->c_n = mlp_create_problem_create_column (p, name, GLP_IV, GLP_DB, 0.0,
1105 1.0, 0.0);
1106 GNUNET_free (name);
1107
1108 /* Add address dependent constraints */
1109 /* Add c1) bandwidth capping: b_t + (-M) * n_t <= 0 */
1110 GNUNET_asprintf (&name, "c1_%s_%s_%p", GNUNET_i2s (&address->peer),
1111 address->plugin, address);
1112 mlpi->r_c1 = mlp_create_problem_create_constraint (p, name, GLP_UP, 0.0, 0.0);
1113 GNUNET_free (name);
1114 /* c1) set b = 1 coefficient */
1115 mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_b, 1, __LINE__);
1116 /* c1) set n = - min (M, quota) coefficient */
1117 cur_bigm = (double) mlp->pv.quota_out[addr_net_index];
1118 if (cur_bigm > mlp->pv.BIG_M)
1119 cur_bigm = (double) mlp->pv.BIG_M;
1120 mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_n, -cur_bigm, __LINE__);
1121
1122 /* Add constraint c 3) minimum bandwidth
1123 * b_t + (-n_t * b_min) >= 0
1124 * */
1125 GNUNET_asprintf (&name, "c3_%s_%s_%p", GNUNET_i2s (&address->peer),
1126 address->plugin, address);
1127 mlpi->r_c3 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0, 0.0);
1128 GNUNET_free (name);
1129
1130 /* c3) set b = 1 coefficient */
1131 mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_b, 1, __LINE__);
1132 /* c3) set n = -b_min coefficient */
1133 mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_n,
1134 -((double ) mlp->pv.b_min), __LINE__);
1135
1136
1137 /* Set coefficient entries in invariant rows */
1138
1139 /* Feasbility */
1140
1141 /* c 4) minimum connections */
1142 mlp_create_problem_set_value (p, p->r_c4, mlpi->c_n, 1, __LINE__);
1143 /* c 2) 1 address peer peer */
1144 mlp_create_problem_set_value (p, peer->r_c2, mlpi->c_n, 1, __LINE__);
1145 /* c 10) obey network specific quotas
1146 * (1)*b_1 + ... + (1)*b_m <= quota_n
1147 */
1148 mlp_create_problem_set_value (p, p->r_quota[addr_net_index], mlpi->c_b, 1,
1149 __LINE__);
1150
1151 /* Optimality */
1152 if (GNUNET_NO == mlp->opt_dbg_feasibility_only)
1153 {
1154 /* c 6) maximize diversity */
1155 mlp_create_problem_set_value (p, p->r_c6, mlpi->c_n, 1, __LINE__);
1156 /* c 9) relativity */
1157 if (GNUNET_YES == mlp->opt_dbg_optimize_relativity)
1158 mlp_create_problem_set_value (p, peer->r_c9, mlpi->c_b, 1, __LINE__);
1159 /* c 8) utility */
1160 if (GNUNET_YES == mlp->opt_dbg_optimize_utility)
1161 mlp_create_problem_set_value (p, p->r_c8, mlpi->c_b, 1, __LINE__);
1162 /* c 7) Optimize quality */
1163 /* For all quality metrics, set quality of this address */
1164 if (GNUNET_YES == mlp->opt_dbg_optimize_quality)
1165 {
1166 mlp_create_problem_set_value (p,
1167 p->r_q[RQ_QUALITY_METRIC_DELAY],
1168 mlpi->c_b,
1169 address->norm_delay.norm,
1170 __LINE__);
1171 mlp_create_problem_set_value (p,
1172 p->r_q[RQ_QUALITY_METRIC_DISTANCE],
1173 mlpi->c_b,
1174 address->norm_distance.norm,
1175 __LINE__);
1176 }
1177 }
1178
1179 return GNUNET_OK;
1180}
1181
1182
1183/**
1184 * Create the invariant columns c4, c6, c10, c8, c7
1185 */
1186static void
1187mlp_create_problem_add_invariant_rows (struct GAS_MLP_Handle *mlp, struct
1188 MLP_Problem *p)
1189{
1190 int c;
1191
1192 /* Feasibility */
1193
1194 /* Row for c4) minimum connection */
1195 /* Number of minimum connections is min(|Peers|, n_min) */
1196 p->r_c4 = mlp_create_problem_create_constraint (p, "c4", GLP_LO,
1197 (mlp->pv.n_min >
1198 p->num_peers) ?
1199 p->num_peers : mlp->pv.n_min,
1200 0.0);
1201
1202 /* Rows for c 10) Enforce network quotas */
1203 for (c = 0; c < GNUNET_NT_COUNT; c++)
1204 {
1205 char *text;
1206 GNUNET_asprintf (&text, "c10_quota_ats_%s",
1207 GNUNET_NT_to_string (mlp->pv.quota_index[c]));
1208 p->r_quota[c] = mlp_create_problem_create_constraint (p, text, GLP_DB, 0.0,
1209 mlp->pv.quota_out[c]);
1210 GNUNET_free (text);
1211 }
1212
1213 /* Optimality */
1214 if (GNUNET_NO == mlp->opt_dbg_feasibility_only)
1215 {
1216 char *name;
1217 /* Add row for c6) Maximize for diversity */
1218 if (GNUNET_YES == mlp->opt_dbg_optimize_diversity)
1219 {
1220 p->r_c6 = mlp_create_problem_create_constraint (p, "c6", GLP_FX, 0.0,
1221 0.0);
1222 /* Set c6 ) Setting -D */
1223 mlp_create_problem_set_value (p, p->r_c6, p->c_d, -1, __LINE__);
1224 }
1225
1226 /* Adding rows for c 8) Maximize utility */
1227 if (GNUNET_YES == mlp->opt_dbg_optimize_utility)
1228 {
1229 p->r_c8 = mlp_create_problem_create_constraint (p, "c8", GLP_FX, 0.0,
1230 0.0);
1231 /* -u */
1232 mlp_create_problem_set_value (p, p->r_c8, p->c_u, -1, __LINE__);
1233 }
1234
1235 /* For all quality metrics:
1236 * c 7) Maximize quality, austerity */
1237 if (GNUNET_YES == mlp->opt_dbg_optimize_quality)
1238 {
1239 for (c = 0; c < mlp->pv.m_q; c++)
1240 {
1241 GNUNET_asprintf (&name,
1242 "c7_q%i_%s", c,
1243 print_quality_type (c));
1244 p->r_q[c] = mlp_create_problem_create_constraint (p, name, GLP_FX, 0.0,
1245 0.0);
1246 GNUNET_free (name);
1247 mlp_create_problem_set_value (p,
1248 p->r_q[c],
1249 p->c_q[c], -1, __LINE__);
1250 }
1251 }
1252 }
1253}
1254
1255
1256/**
1257 * Create the invariant columns d, u, r, q0 ... qm
1258 */
1259static void
1260mlp_create_problem_add_invariant_columns (struct GAS_MLP_Handle *mlp, struct
1261 MLP_Problem *p)
1262{
1263 if (GNUNET_NO == mlp->opt_dbg_feasibility_only)
1264 {
1265 char *name;
1266 int c;
1267
1268 /* Diversity d column */
1269 if (GNUNET_YES == mlp->opt_dbg_optimize_diversity)
1270 p->c_d = mlp_create_problem_create_column (p, "d", GLP_CV, GLP_LO, 0.0,
1271 0.0, mlp->pv.co_D);
1272
1273 /* Utilization u column */
1274 if (GNUNET_YES == mlp->opt_dbg_optimize_utility)
1275 p->c_u = mlp_create_problem_create_column (p, "u", GLP_CV, GLP_LO, 0.0,
1276 0.0, mlp->pv.co_U);
1277
1278 /* Relativity r column */
1279 if (GNUNET_YES == mlp->opt_dbg_optimize_relativity)
1280 p->c_r = mlp_create_problem_create_column (p, "r", GLP_CV, GLP_LO, 0.0,
1281 0.0, mlp->pv.co_R);
1282
1283 /* Quality metric columns */
1284 if (GNUNET_YES == mlp->opt_dbg_optimize_quality)
1285 {
1286 for (c = 0; c < mlp->pv.m_q; c++)
1287 {
1288 GNUNET_asprintf (&name, "q_%u", c);
1289 p->c_q[c] = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO,
1290 0.0, 0.0,
1291 mlp->pv.co_Q[c]);
1292 GNUNET_free (name);
1293 }
1294 }
1295 }
1296}
1297
1298
1299/**
1300 * Create the MLP problem
1301 *
1302 * @param mlp the MLP handle
1303 * @return #GNUNET_OK or #GNUNET_SYSERR
1304 */
1305static int
1306mlp_create_problem (struct GAS_MLP_Handle *mlp)
1307{
1308 struct MLP_Problem *p = &mlp->p;
1309 int res = GNUNET_OK;
1310
1311 GNUNET_assert (p->prob == NULL);
1312 GNUNET_assert (p->ia == NULL);
1313 GNUNET_assert (p->ja == NULL);
1314 GNUNET_assert (p->ar == NULL);
1315 /* Reset MLP problem struct */
1316
1317 /* create the glpk problem */
1318 p->prob = glp_create_prob ();
1319 GNUNET_assert (NULL != p->prob);
1320 p->num_peers = mlp_create_problem_count_peers (mlp->requested_peers,
1321 mlp->env->addresses);
1322 p->num_addresses = mlp_create_problem_count_addresses (mlp->requested_peers,
1323 mlp->env->addresses);
1324
1325 /* Create problem matrix: 10 * #addresses + #q * #addresses + #q, + #peer + 2 + 1 */
1326 p->num_elements = (10 * p->num_addresses + mlp->pv.m_q * p->num_addresses
1327 + mlp->pv.m_q + p->num_peers + 2 + 1);
1328 LOG (GNUNET_ERROR_TYPE_DEBUG,
1329 "Rebuilding problem for %u peer(s) and %u addresse(s) and %u quality metrics == %u elements\n",
1330 p->num_peers,
1331 p->num_addresses,
1332 mlp->pv.m_q,
1333 p->num_elements);
1334
1335 /* Set a problem name */
1336 glp_set_prob_name (p->prob, "GNUnet ATS bandwidth distribution");
1337 /* Set optimization direction to maximize */
1338 glp_set_obj_dir (p->prob, GLP_MAX);
1339
1340 /* Create problem matrix */
1341 /* last +1 caused by glpk index starting with one: [1..elements]*/
1342 p->ci = 1;
1343 /* row index */
1344 p->ia = GNUNET_malloc (p->num_elements * sizeof(int));
1345 /* column index */
1346 p->ja = GNUNET_malloc (p->num_elements * sizeof(int));
1347 /* coefficient */
1348 p->ar = GNUNET_malloc (p->num_elements * sizeof(double));
1349
1350 if ((NULL == p->ia) || (NULL == p->ja) || (NULL == p->ar))
1351 {
1352 LOG (GNUNET_ERROR_TYPE_ERROR, _ (
1353 "Problem size too large, cannot allocate memory!\n"));
1354 return GNUNET_SYSERR;
1355 }
1356
1357 /* Adding invariant columns */
1358 mlp_create_problem_add_invariant_columns (mlp, p);
1359
1360 /* Adding address independent constraint rows */
1361 mlp_create_problem_add_invariant_rows (mlp, p);
1362
1363 /* Adding address dependent columns constraint rows */
1364 GNUNET_CONTAINER_multipeermap_iterate (mlp->env->addresses,
1365 &
1366 mlp_create_problem_add_address_information,
1367 mlp);
1368
1369 /* Load the matrix */
1370 LOG (GNUNET_ERROR_TYPE_DEBUG, "Loading matrix\n");
1371 glp_load_matrix (p->prob, (p->ci) - 1, p->ia, p->ja, p->ar);
1372 if (GNUNET_YES == mlp->opt_dbg_autoscale_problem)
1373 {
1374 glp_scale_prob (p->prob, GLP_SF_AUTO);
1375 }
1376
1377 return res;
1378}
1379
1380
1381/**
1382 * Solves the LP problem
1383 *
1384 * @param mlp the MLP Handle
1385 * @return #GNUNET_OK if could be solved, #GNUNET_SYSERR on failure
1386 */
1387static int
1388mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp)
1389{
1390 int res = 0;
1391 int res_status = 0;
1392
1393 res = glp_simplex (mlp->p.prob, &mlp->control_param_lp);
1394 if (0 == res)
1395 LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem: %s\n",
1396 mlp_solve_to_string (res));
1397 else
1398 LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem failed: %s\n",
1399 mlp_solve_to_string (res));
1400
1401 /* Analyze problem status */
1402 res_status = glp_get_status (mlp->p.prob);
1403 switch (res_status)
1404 {
1405 case GLP_OPT: /* solution is optimal */
1406 LOG (GNUNET_ERROR_TYPE_INFO,
1407 "Solving LP problem: %s, %s\n",
1408 mlp_solve_to_string (res),
1409 mlp_status_to_string (res_status));
1410 return GNUNET_OK;
1411
1412 default:
1413 LOG (GNUNET_ERROR_TYPE_ERROR,
1414 "Solving LP problem failed: %s %s\n",
1415 mlp_solve_to_string (res),
1416 mlp_status_to_string (res_status));
1417 return GNUNET_SYSERR;
1418 }
1419}
1420
1421
1422/**
1423 * Propagates the results when MLP problem was solved
1424 *
1425 * @param cls the MLP handle
1426 * @param key the peer identity
1427 * @param value the address
1428 * @return #GNUNET_OK to continue
1429 */
1430static int
1431mlp_propagate_results (void *cls,
1432 const struct GNUNET_PeerIdentity *key,
1433 void *value)
1434{
1435 struct GAS_MLP_Handle *mlp = cls;
1436 struct ATS_Address *address;
1437 struct MLP_information *mlpi;
1438 double mlp_bw_in = MLP_NaN;
1439 double mlp_bw_out = MLP_NaN;
1440 double mlp_use = MLP_NaN;
1441
1442 /* Check if we have to add this peer due to a pending request */
1443 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (mlp->requested_peers,
1444 key))
1445 {
1446 return GNUNET_OK;
1447 }
1448 address = value;
1449 GNUNET_assert (address->solver_information != NULL);
1450 mlpi = address->solver_information;
1451
1452 mlp_bw_in = glp_mip_col_val (mlp->p.prob, mlpi->c_b);/* FIXME */
1453 if (mlp_bw_in > (double) UINT32_MAX)
1454 {
1455 LOG (GNUNET_ERROR_TYPE_DEBUG,
1456 "Overflow in assigned bandwidth, reducing ...\n");
1457 mlp_bw_in = (double) UINT32_MAX;
1458 }
1459 mlp_bw_out = glp_mip_col_val (mlp->p.prob, mlpi->c_b);
1460 if (mlp_bw_out > (double) UINT32_MAX)
1461 {
1462 LOG (GNUNET_ERROR_TYPE_DEBUG,
1463 "Overflow in assigned bandwidth, reducing ...\n");
1464 mlp_bw_out = (double) UINT32_MAX;
1465 }
1466 mlp_use = glp_mip_col_val (mlp->p.prob, mlpi->c_n);
1467
1468 /*
1469 * Debug: solution
1470 * LOG (GNUNET_ERROR_TYPE_INFO, "MLP result address: `%s' `%s' length %u session %u, mlp use %.3f\n",
1471 * GNUNET_i2s(&address->peer), address->plugin,
1472 * address->addr_len, address->session_id);
1473 */
1474
1475 if (GLP_YES == mlp_use)
1476 {
1477 /* This address was selected by the solver to be used */
1478 mlpi->n = GNUNET_YES;
1479 if (GNUNET_NO == address->active)
1480 {
1481 /* Address was not used before, enabling address */
1482 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : enabling address\n",
1483 (1 == mlp_use) ? "[x]" : "[ ]", mlp_bw_out);
1484 address->active = GNUNET_YES;
1485 address->assigned_bw_in = mlp_bw_in;
1486 mlpi->b_in = mlp_bw_in;
1487 address->assigned_bw_out = mlp_bw_out;
1488 mlpi->b_out = mlp_bw_out;
1489 if ((NULL == mlp->exclude_peer) || (0 != GNUNET_memcmp (&address->peer,
1490 mlp->exclude_peer)))
1491 mlp->env->bandwidth_changed_cb (mlp->env->cls, address);
1492 return GNUNET_OK;
1493 }
1494 else if (GNUNET_YES == address->active)
1495 {
1496 /* Address was used before, check for bandwidth change */
1497 if ((mlp_bw_out != address->assigned_bw_out) ||
1498 (mlp_bw_in != address->assigned_bw_in))
1499 {
1500 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : bandwidth changed\n",
1501 (1 == mlp_use) ? "[x]" : "[ ]", mlp_bw_out);
1502 address->assigned_bw_in = mlp_bw_in;
1503 mlpi->b_in = mlp_bw_in;
1504 address->assigned_bw_out = mlp_bw_out;
1505 mlpi->b_out = mlp_bw_out;
1506 if ((NULL == mlp->exclude_peer) || (0 != GNUNET_memcmp (&address->peer,
1507 mlp->
1508 exclude_peer)))
1509 mlp->env->bandwidth_changed_cb (mlp->env->cls, address);
1510 return GNUNET_OK;
1511 }
1512 }
1513 else
1514 GNUNET_break (0);
1515 }
1516 else if (GLP_NO == mlp_use)
1517 {
1518 /* This address was selected by the solver to be not used */
1519 mlpi->n = GNUNET_NO;
1520 if (GNUNET_NO == address->active)
1521 {
1522 /* Address was not used before, nothing to do */
1523 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : no change\n",
1524 (1 == mlp_use) ? "[x]" : "[ ]", mlp_bw_out);
1525 return GNUNET_OK;
1526 }
1527 else if (GNUNET_YES == address->active)
1528 {
1529 /* Address was used before, disabling address */
1530 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : disabling address\n",
1531 (1 == mlp_use) ? "[x]" : "[ ]", mlp_bw_out);
1532 address->active = GNUNET_NO;
1533 /* Set bandwidth to 0 */
1534 address->assigned_bw_in = 0;
1535 mlpi->b_in = 0;
1536 address->assigned_bw_out = 0;
1537 mlpi->b_out = 0;
1538 return GNUNET_OK;
1539 }
1540 else
1541 GNUNET_break (0);
1542 }
1543 else
1544 GNUNET_break (0);
1545
1546 return GNUNET_OK;
1547}
1548
1549
1550static void
1551notify (struct GAS_MLP_Handle *mlp,
1552 enum GAS_Solver_Operation op,
1553 enum GAS_Solver_Status stat,
1554 enum GAS_Solver_Additional_Information add)
1555{
1556 mlp->env->info_cb (mlp->env->cls,
1557 op,
1558 stat,
1559 add);
1560}
1561
1562
1563static void
1564mlp_branch_and_cut_cb (glp_tree *tree, void *info)
1565{
1566 struct GAS_MLP_Handle *mlp = info;
1567 double mlp_obj = 0;
1568
1569 switch (glp_ios_reason (tree))
1570 {
1571 case GLP_ISELECT:
1572 /* Do nothing here */
1573 break;
1574
1575 case GLP_IPREPRO:
1576 /* Do nothing here */
1577 break;
1578
1579 case GLP_IROWGEN:
1580 /* Do nothing here */
1581 break;
1582
1583 case GLP_IHEUR:
1584 /* Do nothing here */
1585 break;
1586
1587 case GLP_ICUTGEN:
1588 /* Do nothing here */
1589 break;
1590
1591 case GLP_IBRANCH:
1592 /* Do nothing here */
1593 break;
1594
1595 case GLP_IBINGO:
1596 /* A better solution was found */
1597 mlp->ps.mlp_gap = glp_ios_mip_gap (tree);
1598 mlp_obj = glp_mip_obj_val (mlp->p.prob);
1599 mlp->ps.lp_mlp_gap = (abs (mlp_obj - mlp->ps.lp_objective_value)) / (abs (
1600 mlp_obj)
1601 +
1602 DBL_EPSILON);
1603
1604 LOG (GNUNET_ERROR_TYPE_INFO,
1605 "Found better integer solution, current gaps: %.3f <= %.3f, %.3f <= %.3f\n",
1606 mlp->ps.mlp_gap, mlp->pv.mip_gap,
1607 mlp->ps.lp_mlp_gap, mlp->pv.lp_mip_gap);
1608
1609 if (mlp->ps.mlp_gap <= mlp->pv.mip_gap)
1610 {
1611 LOG (GNUNET_ERROR_TYPE_INFO,
1612 "Current LP/MLP gap of %.3f smaller than tolerated gap of %.3f, terminating search\n",
1613 mlp->ps.lp_mlp_gap, mlp->pv.lp_mip_gap);
1614 glp_ios_terminate (tree);
1615 }
1616
1617 if (mlp->ps.lp_mlp_gap <= mlp->pv.lp_mip_gap)
1618 {
1619 LOG (GNUNET_ERROR_TYPE_INFO,
1620 "Current LP/MLP gap of %.3f smaller than tolerated gap of %.3f, terminating search\n",
1621 mlp->ps.lp_mlp_gap, mlp->pv.lp_mip_gap);
1622 glp_ios_terminate (tree);
1623 }
1624
1625 break;
1626
1627 default:
1628 break;
1629 }
1630 // GNUNET_break (0);
1631}
1632
1633
1634/**
1635 * Solves the MLP problem
1636 *
1637 * @param solver the MLP Handle
1638 * @return #GNUNET_OK if could be solved, #GNUNET_SYSERR on failure
1639 */
1640static int
1641GAS_mlp_solve_problem (void *solver)
1642{
1643 struct GAS_MLP_Handle *mlp = solver;
1644 char *filename;
1645 int res_lp = 0;
1646 int mip_res = 0;
1647 int mip_status = 0;
1648
1649 struct GNUNET_TIME_Absolute start_total;
1650 struct GNUNET_TIME_Absolute start_cur_op;
1651 struct GNUNET_TIME_Relative dur_total;
1652 struct GNUNET_TIME_Relative dur_setup;
1653 struct GNUNET_TIME_Relative dur_lp;
1654 struct GNUNET_TIME_Relative dur_mlp;
1655
1656 GNUNET_assert (NULL != solver);
1657 dur_lp = GNUNET_TIME_UNIT_ZERO;
1658
1659 if (GNUNET_YES == mlp->stat_bulk_lock)
1660 {
1661 mlp->stat_bulk_requests++;
1662 return GNUNET_NO;
1663 }
1664 notify (mlp, GAS_OP_SOLVE_START, GAS_STAT_SUCCESS,
1665 (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL :
1666 GAS_INFO_UPDATED);
1667 start_total = GNUNET_TIME_absolute_get ();
1668
1669 if (0 == GNUNET_CONTAINER_multipeermap_size (mlp->requested_peers))
1670 {
1671 notify (mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE);
1672 return GNUNET_OK; /* No pending requests */
1673 }
1674 if (0 == GNUNET_CONTAINER_multipeermap_size (mlp->env->addresses))
1675 {
1676 notify (mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE);
1677 return GNUNET_OK; /* No addresses available */
1678 }
1679
1680 if ((GNUNET_NO == mlp->stat_mlp_prob_changed)
1681 && (GNUNET_NO == mlp->stat_mlp_prob_updated))
1682 {
1683 LOG (GNUNET_ERROR_TYPE_DEBUG, "No changes to problem\n");
1684 notify (mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE);
1685 return GNUNET_OK;
1686 }
1687 if (GNUNET_YES == mlp->stat_mlp_prob_changed)
1688 {
1689 LOG (GNUNET_ERROR_TYPE_DEBUG, "Problem size changed, rebuilding\n");
1690 notify (mlp, GAS_OP_SOLVE_SETUP_START, GAS_STAT_SUCCESS, GAS_INFO_FULL);
1691 mlp_delete_problem (mlp);
1692 if (GNUNET_SYSERR == mlp_create_problem (mlp))
1693 {
1694 notify (mlp, GAS_OP_SOLVE_SETUP_STOP, GAS_STAT_FAIL, GAS_INFO_FULL);
1695 return GNUNET_SYSERR;
1696 }
1697 notify (mlp, GAS_OP_SOLVE_SETUP_STOP, GAS_STAT_SUCCESS, GAS_INFO_FULL);
1698 if (GNUNET_NO == mlp->opt_dbg_intopt_presolver)
1699 {
1700 mlp->control_param_lp.presolve = GLP_YES; /* LP presolver, we need lp solution */
1701 mlp->control_param_mlp.presolve = GNUNET_NO; /* No presolver, we have LP solution */
1702 }
1703 else
1704 {
1705 mlp->control_param_lp.presolve = GNUNET_NO; /* LP presolver, we need lp solution */
1706 mlp->control_param_mlp.presolve = GLP_YES; /* No presolver, we have LP solution */
1707 dur_lp = GNUNET_TIME_UNIT_ZERO;
1708 }
1709 }
1710 else
1711 {
1712 LOG (GNUNET_ERROR_TYPE_DEBUG, "Problem was updated, resolving\n");
1713 }
1714
1715 /* Reset solution info */
1716 mlp->ps.lp_objective_value = 0.0;
1717 mlp->ps.mlp_gap = 1.0;
1718 mlp->ps.mlp_objective_value = 0.0;
1719 mlp->ps.lp_mlp_gap = 0.0;
1720
1721 dur_setup = GNUNET_TIME_absolute_get_duration (start_total);
1722
1723 /* Run LP solver */
1724 if (GNUNET_NO == mlp->opt_dbg_intopt_presolver)
1725 {
1726 notify (mlp, GAS_OP_SOLVE_MLP_LP_START, GAS_STAT_SUCCESS,
1727 (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL :
1728 GAS_INFO_UPDATED);
1729 LOG (GNUNET_ERROR_TYPE_DEBUG,
1730 "Running LP solver %s\n",
1731 (GLP_YES == mlp->control_param_lp.presolve) ? "with presolver" :
1732 "without presolver");
1733 start_cur_op = GNUNET_TIME_absolute_get ();
1734
1735 /* Solve LP */
1736 /* Only for debugging:
1737 * Always use LP presolver:
1738 * mlp->control_param_lp.presolve = GLP_YES; */
1739 res_lp = mlp_solve_lp_problem (mlp);
1740 if (GNUNET_OK == res_lp)
1741 {
1742 mlp->ps.lp_objective_value = glp_get_obj_val (mlp->p.prob);
1743 LOG (GNUNET_ERROR_TYPE_DEBUG,
1744 "LP solution was: %.3f\n",
1745 mlp->ps.lp_objective_value);
1746 }
1747
1748 dur_lp = GNUNET_TIME_absolute_get_duration (start_cur_op);
1749 notify (mlp, GAS_OP_SOLVE_MLP_LP_STOP,
1750 (GNUNET_OK == res_lp) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL,
1751 (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL :
1752 GAS_INFO_UPDATED);
1753 }
1754
1755 if (GNUNET_YES == mlp->opt_dbg_intopt_presolver)
1756 res_lp = GNUNET_OK;
1757
1758 /* Run MLP solver */
1759 if ((GNUNET_OK == res_lp) || (GNUNET_YES == mlp->opt_dbg_intopt_presolver))
1760 {
1761 LOG (GNUNET_ERROR_TYPE_DEBUG, "Running MLP solver \n");
1762 notify (mlp, GAS_OP_SOLVE_MLP_MLP_START, GAS_STAT_SUCCESS,
1763 (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL :
1764 GAS_INFO_UPDATED);
1765 start_cur_op = GNUNET_TIME_absolute_get ();
1766
1767 /* Solve MIP */
1768
1769 /* Only for debugging, always use LP presolver */
1770 if (GNUNET_YES == mlp->opt_dbg_intopt_presolver)
1771 mlp->control_param_mlp.presolve = GNUNET_YES;
1772
1773 mip_res = glp_intopt (mlp->p.prob, &mlp->control_param_mlp);
1774 switch (mip_res)
1775 {
1776 case 0:
1777 /* Successful */
1778 LOG (GNUNET_ERROR_TYPE_INFO,
1779 "Solving MLP problem: %s\n",
1780 mlp_solve_to_string (mip_res));
1781 break;
1782
1783 case GLP_ETMLIM: /* Time limit reached */
1784 case GLP_EMIPGAP: /* MIP gap tolerance limit reached */
1785 case GLP_ESTOP: /* Solver was instructed to stop*/
1786 /* Semi-successful */
1787 LOG (GNUNET_ERROR_TYPE_INFO,
1788 "Solving MLP problem solution was interupted: %s\n",
1789 mlp_solve_to_string (mip_res));
1790 break;
1791
1792 case GLP_EBOUND:
1793 case GLP_EROOT:
1794 case GLP_ENOPFS:
1795 case GLP_ENODFS:
1796 case GLP_EFAIL:
1797 default:
1798 /* Fail */
1799 LOG (GNUNET_ERROR_TYPE_INFO,
1800 "Solving MLP problem failed: %s\n",
1801 mlp_solve_to_string (mip_res));
1802 break;
1803 }
1804
1805 /* Analyze problem status */
1806 mip_status = glp_mip_status (mlp->p.prob);
1807 switch (mip_status)
1808 {
1809 case GLP_OPT: /* solution is optimal */
1810 LOG (GNUNET_ERROR_TYPE_WARNING,
1811 "Solution of MLP problem is optimal: %s, %s\n",
1812 mlp_solve_to_string (mip_res),
1813 mlp_status_to_string (mip_status));
1814 mip_res = GNUNET_OK;
1815 break;
1816
1817 case GLP_FEAS: /* solution is feasible but not proven optimal */
1818
1819 if ((mlp->ps.mlp_gap <= mlp->pv.mip_gap) ||
1820 (mlp->ps.lp_mlp_gap <= mlp->pv.lp_mip_gap))
1821 {
1822 LOG (GNUNET_ERROR_TYPE_INFO,
1823 "Solution of MLP problem is feasible and solution within gap constraints: %s, %s\n",
1824 mlp_solve_to_string (mip_res),
1825 mlp_status_to_string (mip_status));
1826 mip_res = GNUNET_OK;
1827 }
1828 else
1829 {
1830 LOG (GNUNET_ERROR_TYPE_WARNING,
1831 "Solution of MLP problem is feasible but solution not within gap constraints: %s, %s\n",
1832 mlp_solve_to_string (mip_res),
1833 mlp_status_to_string (mip_status));
1834 mip_res = GNUNET_SYSERR;
1835 }
1836 break;
1837
1838 case GLP_UNDEF: /* Solution undefined */
1839 case GLP_NOFEAS: /* No feasible solution */
1840 default:
1841 LOG (GNUNET_ERROR_TYPE_ERROR,
1842 "Solving MLP problem failed: %s %s\n",
1843 mlp_solve_to_string (mip_res),
1844 mlp_status_to_string (mip_status));
1845 mip_res = GNUNET_SYSERR;
1846 break;
1847 }
1848
1849 dur_mlp = GNUNET_TIME_absolute_get_duration (start_cur_op);
1850 dur_total = GNUNET_TIME_absolute_get_duration (start_total);
1851
1852 notify (mlp, GAS_OP_SOLVE_MLP_MLP_STOP,
1853 (GNUNET_OK == mip_res) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL,
1854 (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL :
1855 GAS_INFO_UPDATED);
1856 }
1857 else
1858 {
1859 /* Do not execute mip solver since lp solution is invalid */
1860 dur_mlp = GNUNET_TIME_UNIT_ZERO;
1861 dur_total = GNUNET_TIME_absolute_get_duration (start_total);
1862
1863 notify (mlp, GAS_OP_SOLVE_MLP_MLP_STOP, GAS_STAT_FAIL,
1864 (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL :
1865 GAS_INFO_UPDATED);
1866 mip_res = GNUNET_SYSERR;
1867 }
1868
1869 /* Notify about end */
1870 notify (mlp, GAS_OP_SOLVE_STOP,
1871 ((GNUNET_OK == mip_res) && (GNUNET_OK == mip_res)) ?
1872 GAS_STAT_SUCCESS : GAS_STAT_FAIL,
1873 (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL :
1874 GAS_INFO_UPDATED);
1875
1876 LOG (GNUNET_ERROR_TYPE_DEBUG,
1877 "Execution time for %s solve: (total/setup/lp/mlp) : %llu %llu %llu %llu\n",
1878 (GNUNET_YES == mlp->stat_mlp_prob_changed) ? "full" : "updated",
1879 (unsigned long long) dur_total.rel_value_us,
1880 (unsigned long long) dur_setup.rel_value_us,
1881 (unsigned long long) dur_lp.rel_value_us,
1882 (unsigned long long) dur_mlp.rel_value_us);
1883
1884 /* Save stats */
1885 mlp->ps.lp_res = res_lp;
1886 mlp->ps.mip_res = mip_res;
1887 mlp->ps.lp_presolv = mlp->control_param_lp.presolve;
1888 mlp->ps.mip_presolv = mlp->control_param_mlp.presolve;
1889 mlp->ps.p_cols = glp_get_num_cols (mlp->p.prob);
1890 mlp->ps.p_rows = glp_get_num_rows (mlp->p.prob);
1891 mlp->ps.p_elements = mlp->p.num_elements;
1892
1893 /* Propagate result*/
1894 notify (mlp, GAS_OP_SOLVE_UPDATE_NOTIFICATION_START,
1895 (GNUNET_OK == res_lp) && (GNUNET_OK == mip_res) ? GAS_STAT_SUCCESS :
1896 GAS_STAT_FAIL,
1897 GAS_INFO_NONE);
1898 if ((GNUNET_OK == res_lp) && (GNUNET_OK == mip_res))
1899 {
1900 GNUNET_CONTAINER_multipeermap_iterate (mlp->env->addresses,
1901 &mlp_propagate_results, mlp);
1902 }
1903 notify (mlp, GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP,
1904 (GNUNET_OK == res_lp) && (GNUNET_OK == mip_res) ? GAS_STAT_SUCCESS :
1905 GAS_STAT_FAIL,
1906 GAS_INFO_NONE);
1907
1908 struct GNUNET_TIME_Absolute time = GNUNET_TIME_absolute_get ();
1909 if ((GNUNET_YES == mlp->opt_dump_problem_all) ||
1910 (mlp->opt_dump_problem_on_fail && ((GNUNET_OK != res_lp) || (GNUNET_OK !=
1911 mip_res))))
1912 {
1913 /* Write problem to disk */
1914 switch (mlp->opt_log_format)
1915 {
1916 case MLP_CPLEX:
1917 GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.cplex",
1918 mlp->p.num_peers,
1919 mlp->p.num_addresses, time.abs_value_us);
1920 glp_write_lp (mlp->p.prob, NULL, filename);
1921 break;
1922
1923 case MLP_GLPK:
1924 GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.glpk",
1925 mlp->p.num_peers,
1926 mlp->p.num_addresses, time.abs_value_us);
1927 glp_write_prob (mlp->p.prob, 0, filename);
1928 break;
1929
1930 case MLP_MPS:
1931 GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.mps", mlp->p.num_peers,
1932 mlp->p.num_addresses, time.abs_value_us);
1933 glp_write_mps (mlp->p.prob, GLP_MPS_FILE, NULL, filename);
1934 break;
1935
1936 default:
1937 break;
1938 }
1939 LOG (GNUNET_ERROR_TYPE_ERROR, "Dumped problem to file: `%s' \n", filename);
1940 GNUNET_free (filename);
1941 }
1942 if ((mlp->opt_dump_solution_all) ||
1943 (mlp->opt_dump_solution_on_fail && ((GNUNET_OK != res_lp) || (GNUNET_OK !=
1944 mip_res))))
1945 {
1946 /* Write solution to disk */
1947 GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.sol", mlp->p.num_peers,
1948 mlp->p.num_addresses, time.abs_value_us);
1949 glp_print_mip (mlp->p.prob, filename);
1950 LOG (GNUNET_ERROR_TYPE_ERROR, "Dumped solution to file: `%s' \n", filename);
1951 GNUNET_free (filename);
1952 }
1953
1954 /* Reset change and update marker */
1955 mlp->control_param_lp.presolve = GLP_NO;
1956 mlp->stat_mlp_prob_updated = GNUNET_NO;
1957 mlp->stat_mlp_prob_changed = GNUNET_NO;
1958
1959 if ((GNUNET_OK == res_lp) && (GNUNET_OK == mip_res))
1960 return GNUNET_OK;
1961 else
1962 return GNUNET_SYSERR;
1963}
1964
1965/**
1966 * Add a single address to the solve
1967 *
1968 * @param solver the solver Handle
1969 * @param address the address to add
1970 * @param network network type of this address
1971 */
1972static void
1973GAS_mlp_address_add (void *solver,
1974 struct ATS_Address *address,
1975 uint32_t network)
1976{
1977 struct GAS_MLP_Handle *mlp = solver;
1978
1979 if (GNUNET_NT_COUNT <= network)
1980 {
1981 GNUNET_break (0);
1982 return;
1983 }
1984
1985 if (NULL == address->solver_information)
1986 {
1987 address->solver_information = GNUNET_new (struct MLP_information);
1988 }
1989 else
1990 LOG (GNUNET_ERROR_TYPE_ERROR,
1991 _ ("Adding address for peer `%s' multiple times\n"),
1992 GNUNET_i2s (&address->peer));
1993
1994 /* Is this peer included in the problem? */
1995 if (NULL ==
1996 GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
1997 &address->peer))
1998 {
1999 /* FIXME: should this be an error? */
2000 LOG (GNUNET_ERROR_TYPE_DEBUG,
2001 "Adding address for peer `%s' without address request\n",
2002 GNUNET_i2s (&address->peer));
2003 return;
2004 }
2005
2006 LOG (GNUNET_ERROR_TYPE_DEBUG,
2007 "Adding address for peer `%s' with address request \n",
2008 GNUNET_i2s (&address->peer));
2009 /* Problem size changed: new address for peer with pending request */
2010 mlp->stat_mlp_prob_changed = GNUNET_YES;
2011 if (GNUNET_YES == mlp->opt_mlp_auto_solve)
2012 GAS_mlp_solve_problem (solver);
2013}
2014
2015
2016/**
2017 * Transport properties for this address have changed
2018 *
2019 * @param solver solver handle
2020 * @param address the address
2021 */
2022static void
2023GAS_mlp_address_property_changed (void *solver,
2024 struct ATS_Address *address)
2025{
2026 struct MLP_information *mlpi = address->solver_information;
2027 struct GAS_MLP_Handle *mlp = solver;
2028
2029 if (NULL == mlp->p.prob)
2030 return; /* There is no MLP problem to update yet */
2031
2032 if (NULL == mlpi)
2033 {
2034 LOG (GNUNET_ERROR_TYPE_INFO,
2035 _ ("Updating address property for peer `%s' %p not added before\n"),
2036 GNUNET_i2s (&address->peer),
2037 address);
2038 GNUNET_break (0);
2039 return;
2040 }
2041 if (NULL ==
2042 GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
2043 &address->peer))
2044 {
2045 /* Peer is not requested, so no need to update problem */
2046 return;
2047 }
2048 LOG (GNUNET_ERROR_TYPE_DEBUG,
2049 "Updating properties for peer `%s'\n",
2050 GNUNET_i2s (&address->peer));
2051
2052 if (GNUNET_YES == mlp->opt_dbg_feasibility_only)
2053 return;
2054
2055 /* Update c7) [r_q[index]][c_b] = f_q * q_averaged[type_index] */
2056 if ((GNUNET_YES ==
2057 mlp_create_problem_update_value (&mlp->p,
2058 mlp->p.r_q[RQ_QUALITY_METRIC_DELAY],
2059 mlpi->c_b,
2060 address->norm_delay.norm,
2061 __LINE__)) ||
2062 (GNUNET_YES ==
2063 mlp_create_problem_update_value (&mlp->p,
2064 mlp->p.r_q[RQ_QUALITY_METRIC_DISTANCE],
2065 mlpi->c_b,
2066 address->norm_distance.norm,
2067 __LINE__)))
2068 {
2069 mlp->stat_mlp_prob_updated = GNUNET_YES;
2070 if (GNUNET_YES == mlp->opt_mlp_auto_solve)
2071 GAS_mlp_solve_problem (solver);
2072 }
2073}
2074
2075
2076/**
2077 * Find the active address in the set of addresses of a peer
2078 * @param cls destination
2079 * @param key peer id
2080 * @param value address
2081 * @return #GNUNET_OK
2082 */
2083static int
2084mlp_get_preferred_address_it (void *cls,
2085 const struct GNUNET_PeerIdentity *key,
2086 void *value)
2087{
2088 static int counter = 0;
2089 struct ATS_Address **aa = cls;
2090 struct ATS_Address *addr = value;
2091 struct MLP_information *mlpi = addr->solver_information;
2092
2093 if (mlpi == NULL)
2094 return GNUNET_YES;
2095
2096 /*
2097 * Debug output
2098 * GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2099 * "MLP [%u] Peer `%s' %s length %u session %u active %s mlp active %s\n",
2100 * counter, GNUNET_i2s (&addr->peer), addr->plugin, addr->addr_len, addr->session_id,
2101 * (GNUNET_YES == addr->active) ? "active" : "inactive",
2102 * (GNUNET_YES == mlpi->n) ? "active" : "inactive");
2103 */
2104
2105 if (GNUNET_YES == mlpi->n)
2106 {
2107 (*aa) = addr;
2108 (*aa)->assigned_bw_in = mlpi->b_in;
2109 (*aa)->assigned_bw_out = mlpi->b_out;
2110 return GNUNET_NO;
2111 }
2112 counter++;
2113 return GNUNET_YES;
2114}
2115
2116
2117static double
2118get_peer_pref_value (struct GAS_MLP_Handle *mlp,
2119 const struct GNUNET_PeerIdentity *peer)
2120{
2121 double res;
2122 const double *preferences;
2123 int c;
2124
2125 preferences = mlp->env->get_preferences (mlp->env->cls, peer);
2126 res = 0.0;
2127 for (c = 0; c < GNUNET_ATS_PREFERENCE_END; c++)
2128 {
2129 /* fprintf (stderr, "VALUE[%u] %s %.3f \n",
2130 * c, GNUNET_i2s (&cur->addr->peer), t[c]); */
2131 res += preferences[c];
2132 }
2133
2134 res /= GNUNET_ATS_PREFERENCE_END;
2135 res += 1.0;
2136
2137 LOG (GNUNET_ERROR_TYPE_DEBUG,
2138 "Peer preference for peer `%s' == %.2f\n",
2139 GNUNET_i2s (peer), res);
2140
2141 return res;
2142}
2143
2144
2145/**
2146 * Get the preferred address for a specific peer
2147 *
2148 * @param solver the MLP Handle
2149 * @param peer the peer
2150 */
2151static void
2152GAS_mlp_get_preferred_address (void *solver,
2153 const struct GNUNET_PeerIdentity *peer)
2154{
2155 struct GAS_MLP_Handle *mlp = solver;
2156 struct ATS_Peer *p;
2157 struct ATS_Address *res;
2158
2159 LOG (GNUNET_ERROR_TYPE_DEBUG,
2160 "Getting preferred address for `%s'\n",
2161 GNUNET_i2s (peer));
2162
2163 /* Is this peer included in the problem? */
2164 if (NULL ==
2165 GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
2166 peer))
2167 {
2168 LOG (GNUNET_ERROR_TYPE_INFO,
2169 "Adding peer `%s' to list of requested_peers with requests\n",
2170 GNUNET_i2s (peer));
2171
2172 p = GNUNET_new (struct ATS_Peer);
2173 p->id = (*peer);
2174 p->f = get_peer_pref_value (mlp, peer);
2175 GNUNET_CONTAINER_multipeermap_put (mlp->requested_peers,
2176 peer, p,
2177 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
2178
2179 /* Added new peer, we have to rebuild problem before solving */
2180 mlp->stat_mlp_prob_changed = GNUNET_YES;
2181
2182 if ((GNUNET_YES == mlp->opt_mlp_auto_solve) &&
2183 (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (
2184 mlp->env->addresses,
2185 peer)))
2186 {
2187 mlp->exclude_peer = peer;
2188 GAS_mlp_solve_problem (mlp);
2189 mlp->exclude_peer = NULL;
2190 }
2191 }
2192 /* Get prefered address */
2193 res = NULL;
2194 GNUNET_CONTAINER_multipeermap_get_multiple (mlp->env->addresses, peer,
2195 &mlp_get_preferred_address_it,
2196 &res);
2197 if (NULL != res)
2198 mlp->env->bandwidth_changed_cb (mlp->env->cls,
2199 res);
2200}
2201
2202
2203/**
2204 * Deletes a single address in the MLP problem
2205 *
2206 * The MLP problem has to be recreated and the problem has to be resolved
2207 *
2208 * @param solver the MLP Handle
2209 * @param address the address to delete
2210 */
2211static void
2212GAS_mlp_address_delete (void *solver,
2213 struct ATS_Address *address)
2214{
2215 struct GAS_MLP_Handle *mlp = solver;
2216 struct MLP_information *mlpi;
2217 struct ATS_Address *res;
2218 int was_active;
2219
2220 mlpi = address->solver_information;
2221 if (NULL != mlpi)
2222 {
2223 /* Remove full address */
2224 GNUNET_free (mlpi);
2225 address->solver_information = NULL;
2226 }
2227 was_active = address->active;
2228 address->active = GNUNET_NO;
2229 address->assigned_bw_in = 0;
2230 address->assigned_bw_out = 0;
2231
2232 /* Is this peer included in the problem? */
2233 if (NULL ==
2234 GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
2235 &address->peer))
2236 {
2237 LOG (GNUNET_ERROR_TYPE_INFO,
2238 "Deleting address for peer `%s' without address request \n",
2239 GNUNET_i2s (&address->peer));
2240 return;
2241 }
2242 LOG (GNUNET_ERROR_TYPE_INFO,
2243 "Deleting address for peer `%s' with address request \n",
2244 GNUNET_i2s (&address->peer));
2245
2246 /* Problem size changed: new address for peer with pending request */
2247 mlp->stat_mlp_prob_changed = GNUNET_YES;
2248 if (GNUNET_YES == mlp->opt_mlp_auto_solve)
2249 {
2250 GAS_mlp_solve_problem (solver);
2251 }
2252 if (GNUNET_YES == was_active)
2253 {
2254 GAS_mlp_get_preferred_address (solver, &address->peer);
2255 res = NULL;
2256 GNUNET_CONTAINER_multipeermap_get_multiple (mlp->env->addresses,
2257 &address->peer,
2258 &mlp_get_preferred_address_it,
2259 &res);
2260 if (NULL == res)
2261 {
2262 /* No alternative address, disconnecting peer */
2263 mlp->env->bandwidth_changed_cb (mlp->env->cls, address);
2264 }
2265 }
2266}
2267
2268
2269/**
2270 * Start a bulk operation
2271 *
2272 * @param solver the solver
2273 */
2274static void
2275GAS_mlp_bulk_start (void *solver)
2276{
2277 struct GAS_MLP_Handle *s = solver;
2278
2279 LOG (GNUNET_ERROR_TYPE_DEBUG,
2280 "Locking solver for bulk operation ...\n");
2281 GNUNET_assert (NULL != solver);
2282 s->stat_bulk_lock++;
2283}
2284
2285
2286static void
2287GAS_mlp_bulk_stop (void *solver)
2288{
2289 struct GAS_MLP_Handle *s = solver;
2290
2291 LOG (GNUNET_ERROR_TYPE_DEBUG,
2292 "Unlocking solver from bulk operation ...\n");
2293 GNUNET_assert (NULL != solver);
2294
2295 if (s->stat_bulk_lock < 1)
2296 {
2297 GNUNET_break (0);
2298 return;
2299 }
2300 s->stat_bulk_lock--;
2301
2302 if (0 < s->stat_bulk_requests)
2303 {
2304 GAS_mlp_solve_problem (solver);
2305 s->stat_bulk_requests = 0;
2306 }
2307}
2308
2309
2310
2311/**
2312 * Stop notifying about address and bandwidth changes for this peer
2313 *
2314 * @param solver the MLP handle
2315 * @param peer the peer
2316 */
2317static void
2318GAS_mlp_stop_get_preferred_address (void *solver,
2319 const struct GNUNET_PeerIdentity *peer)
2320{
2321 struct GAS_MLP_Handle *mlp = solver;
2322 struct ATS_Peer *p = NULL;
2323
2324 GNUNET_assert (NULL != solver);
2325 GNUNET_assert (NULL != peer);
2326 if (NULL != (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
2327 peer)))
2328 {
2329 GNUNET_assert (GNUNET_YES ==
2330 GNUNET_CONTAINER_multipeermap_remove (mlp->requested_peers,
2331 peer, p));
2332 GNUNET_free (p);
2333
2334 mlp->stat_mlp_prob_changed = GNUNET_YES;
2335 if (GNUNET_YES == mlp->opt_mlp_auto_solve)
2336 {
2337 GAS_mlp_solve_problem (solver);
2338 }
2339 }
2340}
2341
2342
2343/**
2344 * Changes the preferences for a peer in the MLP problem
2345 *
2346 * @param solver the MLP Handle
2347 * @param peer the peer
2348 * @param kind the kind to change the preference
2349 * @param pref_rel the relative score
2350 */
2351static void
2352GAS_mlp_address_change_preference (void *solver,
2353 const struct GNUNET_PeerIdentity *peer,
2354 enum GNUNET_ATS_PreferenceKind kind,
2355 double pref_rel)
2356{
2357 struct GAS_MLP_Handle *mlp = solver;
2358 struct ATS_Peer *p;
2359
2360 LOG (GNUNET_ERROR_TYPE_DEBUG,
2361 "Changing preference for address for peer `%s' to %.2f\n",
2362 GNUNET_i2s (peer),
2363 pref_rel);
2364
2365 GNUNET_STATISTICS_update (mlp->env->stats,
2366 "# LP address preference changes", 1, GNUNET_NO);
2367 /* Update the constraints with changed preferences */
2368
2369
2370
2371 /* Update relativity constraint c9 */
2372 if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers,
2373 peer)))
2374 {
2375 LOG (GNUNET_ERROR_TYPE_INFO,
2376 "Updating preference for unknown peer `%s'\n",
2377 GNUNET_i2s (peer));
2378 return;
2379 }
2380
2381 if (GNUNET_NO == mlp->opt_dbg_feasibility_only)
2382 {
2383 p->f = get_peer_pref_value (mlp, peer);
2384 mlp_create_problem_update_value (&mlp->p,
2385 p->r_c9,
2386 mlp->p.c_r,
2387 -p->f,
2388 __LINE__);
2389
2390 /* Problem size changed: new address for peer with pending request */
2391 mlp->stat_mlp_prob_updated = GNUNET_YES;
2392 if (GNUNET_YES == mlp->opt_mlp_auto_solve)
2393 GAS_mlp_solve_problem (solver);
2394 }
2395}
2396
2397
2398/**
2399 * Get application feedback for a peer
2400 *
2401 * @param solver the solver handle
2402 * @param application the application
2403 * @param peer the peer to change the preference for
2404 * @param scope the time interval for this feedback: [now - scope .. now]
2405 * @param kind the kind to change the preference
2406 * @param score the score
2407 */
2408static void
2409GAS_mlp_address_preference_feedback (void *solver,
2410 struct GNUNET_SERVICE_Client *application,
2411 const struct GNUNET_PeerIdentity *peer,
2412 const struct GNUNET_TIME_Relative scope,
2413 enum GNUNET_ATS_PreferenceKind kind,
2414 double score)
2415{
2416 struct GAS_PROPORTIONAL_Handle *s = solver;
2417
2418 GNUNET_assert (NULL != solver);
2419 GNUNET_assert (NULL != peer);
2420 GNUNET_assert (NULL != s);
2421}
2422
2423
2424static int
2425mlp_free_peers (void *cls,
2426 const struct GNUNET_PeerIdentity *key, void *value)
2427{
2428 struct GNUNET_CONTAINER_MultiPeerMap *map = cls;
2429 struct ATS_Peer *p = value;
2430
2431 GNUNET_assert (GNUNET_YES ==
2432 GNUNET_CONTAINER_multipeermap_remove (map, key, value));
2433 GNUNET_free (p);
2434
2435 return GNUNET_OK;
2436}
2437
2438
2439/**
2440 * Shutdown the MLP problem solving component
2441 *
2442 * @param cls the solver handle
2443 * @return NULL
2444 */
2445void *
2446libgnunet_plugin_ats_mlp_done (void *cls)
2447{
2448 struct GNUNET_ATS_SolverFunctions *sf = cls;
2449 struct GAS_MLP_Handle *mlp = sf->cls;
2450
2451 LOG (GNUNET_ERROR_TYPE_DEBUG,
2452 "Shutting down mlp solver\n");
2453 mlp_delete_problem (mlp);
2454 GNUNET_CONTAINER_multipeermap_iterate (mlp->requested_peers,
2455 &mlp_free_peers,
2456 mlp->requested_peers);
2457 GNUNET_CONTAINER_multipeermap_destroy (mlp->requested_peers);
2458 mlp->requested_peers = NULL;
2459
2460 /* Clean up GLPK environment */
2461 glp_free_env ();
2462 GNUNET_free (mlp);
2463
2464 LOG (GNUNET_ERROR_TYPE_DEBUG,
2465 "Shutdown down of mlp solver complete\n");
2466 return NULL;
2467}
2468
2469
2470void *
2471libgnunet_plugin_ats_mlp_init (void *cls)
2472{
2473 static struct GNUNET_ATS_SolverFunctions sf;
2474 struct GNUNET_ATS_PluginEnvironment *env = cls;
2475 struct GAS_MLP_Handle *mlp = GNUNET_new (struct GAS_MLP_Handle);
2476 float f_tmp;
2477 unsigned long long tmp;
2478 unsigned int b_min;
2479 unsigned int n_min;
2480 int c;
2481 char *outputformat;
2482
2483 struct GNUNET_TIME_Relative max_duration;
2484 long long unsigned int max_iterations;
2485
2486 /* Init GLPK environment */
2487 int res = glp_init_env ();
2488
2489 switch (res)
2490 {
2491 case 0:
2492 LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
2493 "initialization successful");
2494 break;
2495
2496 case 1:
2497 LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
2498 "environment is already initialized");
2499 break;
2500
2501 case 2:
2502 LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
2503 "initialization failed (insufficient memory)");
2504 GNUNET_free (mlp);
2505 return NULL;
2506 break;
2507
2508 case 3:
2509 LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
2510 "initialization failed (unsupported programming model)");
2511 GNUNET_free (mlp);
2512 return NULL;
2513 break;
2514
2515 default:
2516 break;
2517 }
2518
2519 mlp->opt_dump_problem_all = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2520 "ats",
2521 "MLP_DUMP_PROBLEM_ALL");
2522 if (GNUNET_SYSERR == mlp->opt_dump_problem_all)
2523 mlp->opt_dump_problem_all = GNUNET_NO;
2524
2525 mlp->opt_dump_solution_all = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2526 "ats",
2527 "MLP_DUMP_SOLUTION_ALL");
2528 if (GNUNET_SYSERR == mlp->opt_dump_solution_all)
2529 mlp->opt_dump_solution_all = GNUNET_NO;
2530
2531 mlp->opt_dump_problem_on_fail = GNUNET_CONFIGURATION_get_value_yesno (
2532 env->cfg,
2533 "ats",
2534 "MLP_DUMP_PROBLEM_ON_FAIL");
2535 if (GNUNET_SYSERR == mlp->opt_dump_problem_on_fail)
2536 mlp->opt_dump_problem_on_fail = GNUNET_NO;
2537
2538 mlp->opt_dump_solution_on_fail = GNUNET_CONFIGURATION_get_value_yesno (
2539 env->cfg,
2540 "ats",
2541 "MLP_DUMP_SOLUTION_ON_FAIL");
2542 if (GNUNET_SYSERR == mlp->opt_dump_solution_on_fail)
2543 mlp->opt_dump_solution_on_fail = GNUNET_NO;
2544
2545 mlp->opt_dbg_glpk_verbose = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2546 "ats",
2547 "MLP_DBG_GLPK_VERBOSE");
2548 if (GNUNET_SYSERR == mlp->opt_dbg_glpk_verbose)
2549 mlp->opt_dbg_glpk_verbose = GNUNET_NO;
2550
2551 mlp->opt_dbg_feasibility_only = GNUNET_CONFIGURATION_get_value_yesno (
2552 env->cfg,
2553 "ats",
2554 "MLP_DBG_FEASIBILITY_ONLY");
2555 if (GNUNET_SYSERR == mlp->opt_dbg_feasibility_only)
2556 mlp->opt_dbg_feasibility_only = GNUNET_NO;
2557 if (GNUNET_YES == mlp->opt_dbg_feasibility_only)
2558 LOG (GNUNET_ERROR_TYPE_WARNING,
2559 "MLP solver is configured to check feasibility only!\n");
2560
2561 mlp->opt_dbg_autoscale_problem = GNUNET_CONFIGURATION_get_value_yesno (
2562 env->cfg,
2563 "ats",
2564 "MLP_DBG_AUTOSCALE_PROBLEM");
2565 if (GNUNET_SYSERR == mlp->opt_dbg_autoscale_problem)
2566 mlp->opt_dbg_autoscale_problem = GNUNET_NO;
2567 if (GNUNET_YES == mlp->opt_dbg_autoscale_problem)
2568 LOG (GNUNET_ERROR_TYPE_WARNING,
2569 "MLP solver is configured automatically scale the problem!\n");
2570
2571 mlp->opt_dbg_intopt_presolver = GNUNET_CONFIGURATION_get_value_yesno (
2572 env->cfg,
2573 "ats",
2574 "MLP_DBG_INTOPT_PRESOLVE");
2575 if (GNUNET_SYSERR == mlp->opt_dbg_intopt_presolver)
2576 mlp->opt_dbg_intopt_presolver = GNUNET_NO;
2577 if (GNUNET_YES == mlp->opt_dbg_intopt_presolver)
2578 LOG (GNUNET_ERROR_TYPE_WARNING,
2579 "MLP solver is configured use the mlp presolver\n");
2580
2581 mlp->opt_dbg_optimize_diversity = GNUNET_CONFIGURATION_get_value_yesno (
2582 env->cfg,
2583 "ats",
2584 "MLP_DBG_OPTIMIZE_DIVERSITY");
2585 if (GNUNET_SYSERR == mlp->opt_dbg_optimize_diversity)
2586 mlp->opt_dbg_optimize_diversity = GNUNET_YES;
2587 if (GNUNET_NO == mlp->opt_dbg_optimize_diversity)
2588 LOG (GNUNET_ERROR_TYPE_WARNING,
2589 "MLP solver is not optimizing for diversity\n");
2590
2591 mlp->opt_dbg_optimize_relativity = GNUNET_CONFIGURATION_get_value_yesno (
2592 env->cfg,
2593 "ats",
2594 "MLP_DBG_OPTIMIZE_RELATIVITY");
2595 if (GNUNET_SYSERR == mlp->opt_dbg_optimize_relativity)
2596 mlp->opt_dbg_optimize_relativity = GNUNET_YES;
2597 if (GNUNET_NO == mlp->opt_dbg_optimize_relativity)
2598 LOG (GNUNET_ERROR_TYPE_WARNING,
2599 "MLP solver is not optimizing for relativity\n");
2600
2601 mlp->opt_dbg_optimize_quality = GNUNET_CONFIGURATION_get_value_yesno (
2602 env->cfg,
2603 "ats",
2604 "MLP_DBG_OPTIMIZE_QUALITY");
2605 if (GNUNET_SYSERR == mlp->opt_dbg_optimize_quality)
2606 mlp->opt_dbg_optimize_quality = GNUNET_YES;
2607 if (GNUNET_NO == mlp->opt_dbg_optimize_quality)
2608 LOG (GNUNET_ERROR_TYPE_WARNING,
2609 "MLP solver is not optimizing for quality\n");
2610
2611 mlp->opt_dbg_optimize_utility = GNUNET_CONFIGURATION_get_value_yesno (
2612 env->cfg,
2613 "ats",
2614 "MLP_DBG_OPTIMIZE_UTILITY");
2615 if (GNUNET_SYSERR == mlp->opt_dbg_optimize_utility)
2616 mlp->opt_dbg_optimize_utility = GNUNET_YES;
2617 if (GNUNET_NO == mlp->opt_dbg_optimize_utility)
2618 LOG (GNUNET_ERROR_TYPE_WARNING,
2619 "MLP solver is not optimizing for utility\n");
2620
2621 if ((GNUNET_NO == mlp->opt_dbg_optimize_utility) &&
2622 (GNUNET_NO == mlp->opt_dbg_optimize_quality) &&
2623 (GNUNET_NO == mlp->opt_dbg_optimize_relativity) &&
2624 (GNUNET_NO == mlp->opt_dbg_optimize_utility) &&
2625 (GNUNET_NO == mlp->opt_dbg_feasibility_only))
2626 {
2627 LOG (GNUNET_ERROR_TYPE_ERROR,
2628 _ (
2629 "MLP solver is not optimizing for anything, changing to feasibility check\n"));
2630 mlp->opt_dbg_feasibility_only = GNUNET_YES;
2631 }
2632
2633 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (env->cfg,
2634 "ats",
2635 "MLP_LOG_FORMAT",
2636 &outputformat))
2637 mlp->opt_log_format = MLP_CPLEX;
2638 else
2639 {
2640 GNUNET_STRINGS_utf8_toupper (outputformat, outputformat);
2641 if (0 == strcmp (outputformat, "MPS"))
2642 {
2643 mlp->opt_log_format = MLP_MPS;
2644 }
2645 else if (0 == strcmp (outputformat, "CPLEX"))
2646 {
2647 mlp->opt_log_format = MLP_CPLEX;
2648 }
2649 else if (0 == strcmp (outputformat, "GLPK"))
2650 {
2651 mlp->opt_log_format = MLP_GLPK;
2652 }
2653 else
2654 {
2655 LOG (GNUNET_ERROR_TYPE_WARNING,
2656 "Invalid log format `%s' in configuration, using CPLEX!\n",
2657 outputformat);
2658 mlp->opt_log_format = MLP_CPLEX;
2659 }
2660 GNUNET_free (outputformat);
2661 }
2662
2663 mlp->pv.BIG_M = (double) BIG_M_VALUE;
2664
2665 mlp->pv.mip_gap = (double) 0.0;
2666 if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
2667 "MLP_MAX_MIP_GAP",
2668 &f_tmp))
2669 {
2670 if ((f_tmp < 0.0) || (f_tmp > 1.0))
2671 {
2672 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"),
2673 "MIP gap", f_tmp);
2674 }
2675 else
2676 {
2677 mlp->pv.mip_gap = f_tmp;
2678 LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n",
2679 "MIP gap", f_tmp);
2680 }
2681 }
2682
2683 mlp->pv.lp_mip_gap = (double) 0.0;
2684 if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
2685 "MLP_MAX_LP_MIP_GAP",
2686 &f_tmp))
2687 {
2688 if ((f_tmp < 0.0) || (f_tmp > 1.0))
2689 {
2690 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"),
2691 "LP/MIP", f_tmp);
2692 }
2693 else
2694 {
2695 mlp->pv.lp_mip_gap = f_tmp;
2696 LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n",
2697 "LP/MIP", f_tmp);
2698 }
2699 }
2700
2701 /* Get timeout for iterations */
2702 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (env->cfg, "ats",
2703 "MLP_MAX_DURATION",
2704 &max_duration))
2705 {
2706 max_duration = MLP_MAX_EXEC_DURATION;
2707 }
2708
2709 /* Get maximum number of iterations */
2710 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
2711 "MLP_MAX_ITERATIONS",
2712 &max_iterations))
2713 {
2714 max_iterations = MLP_MAX_ITERATIONS;
2715 }
2716
2717 /* Get diversity coefficient from configuration */
2718 mlp->pv.co_D = MLP_DEFAULT_D;
2719 if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
2720 "MLP_COEFFICIENT_D",
2721 &f_tmp))
2722 {
2723 if ((f_tmp < 0.0))
2724 {
2725 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"),
2726 "MLP_COEFFICIENT_D", f_tmp);
2727 }
2728 else
2729 {
2730 mlp->pv.co_D = f_tmp;
2731 LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n",
2732 "MLP_COEFFICIENT_D", f_tmp);
2733 }
2734 }
2735
2736 /* Get relativity coefficient from configuration */
2737 mlp->pv.co_R = MLP_DEFAULT_R;
2738 if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
2739 "MLP_COEFFICIENT_R",
2740 &f_tmp))
2741 {
2742 if ((f_tmp < 0.0))
2743 {
2744 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"),
2745 "MLP_COEFFICIENT_R", f_tmp);
2746 }
2747 else
2748 {
2749 mlp->pv.co_R = f_tmp;
2750 LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n",
2751 "MLP_COEFFICIENT_R", f_tmp);
2752 }
2753 }
2754
2755
2756 /* Get utilization coefficient from configuration */
2757 mlp->pv.co_U = MLP_DEFAULT_U;
2758 if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
2759 "MLP_COEFFICIENT_U",
2760 &f_tmp))
2761 {
2762 if ((f_tmp < 0.0))
2763 {
2764 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"),
2765 "MLP_COEFFICIENT_U", f_tmp);
2766 }
2767 else
2768 {
2769 mlp->pv.co_U = f_tmp;
2770 LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n",
2771 "MLP_COEFFICIENT_U", f_tmp);
2772 }
2773 }
2774
2775 /* Get quality metric coefficients from configuration */
2776 for (c = 0; c < RQ_QUALITY_METRIC_COUNT; c++)
2777 {
2778 /* initialize quality coefficients with default value 1.0 */
2779 mlp->pv.co_Q[c] = MLP_DEFAULT_QUALITY;
2780 }
2781
2782
2783 if (GNUNET_OK ==
2784 GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
2785 "MLP_COEFFICIENT_QUALITY_DELAY",
2786 &tmp))
2787 mlp->pv.co_Q[RQ_QUALITY_METRIC_DELAY] = (double) tmp / 100;
2788 else
2789 mlp->pv.co_Q[RQ_QUALITY_METRIC_DELAY] = MLP_DEFAULT_QUALITY;
2790
2791 if (GNUNET_OK ==
2792 GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
2793 "MLP_COEFFICIENT_QUALITY_DISTANCE",
2794 &tmp))
2795 mlp->pv.co_Q[RQ_QUALITY_METRIC_DISTANCE] = (double) tmp / 100;
2796 else
2797 mlp->pv.co_Q[RQ_QUALITY_METRIC_DISTANCE] = MLP_DEFAULT_QUALITY;
2798
2799 /* Get minimum bandwidth per used address from configuration */
2800 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
2801 "MLP_MIN_BANDWIDTH",
2802 &tmp))
2803 b_min = tmp;
2804 else
2805 {
2806 b_min = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
2807 }
2808
2809 /* Get minimum number of connections from configuration */
2810 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats",
2811 "MLP_MIN_CONNECTIONS",
2812 &tmp))
2813 n_min = tmp;
2814 else
2815 n_min = MLP_DEFAULT_MIN_CONNECTIONS;
2816
2817 /* Init network quotas */
2818 for (c = 0; c < GNUNET_NT_COUNT; c++)
2819 {
2820 mlp->pv.quota_index[c] = c;
2821 mlp->pv.quota_out[c] = env->out_quota[c];
2822 mlp->pv.quota_in[c] = env->in_quota[c];
2823
2824 LOG (GNUNET_ERROR_TYPE_INFO,
2825 "Quota for network `%s' (in/out) %llu/%llu\n",
2826 GNUNET_NT_to_string (c),
2827 mlp->pv.quota_out[c],
2828 mlp->pv.quota_in[c]);
2829 /* Check if defined quota could make problem unsolvable */
2830 if ((n_min * b_min) > mlp->pv.quota_out[c])
2831 {
2832 LOG (GNUNET_ERROR_TYPE_INFO,
2833 _ (
2834 "Adjusting inconsistent outbound quota configuration for network `%s', is %llu must be at least %llu\n"),
2835 GNUNET_NT_to_string (mlp->pv.quota_index[c]),
2836 mlp->pv.quota_out[c],
2837 (n_min * b_min));
2838 mlp->pv.quota_out[c] = (n_min * b_min);
2839 }
2840 if ((n_min * b_min) > mlp->pv.quota_in[c])
2841 {
2842 LOG (GNUNET_ERROR_TYPE_INFO,
2843 _ (
2844 "Adjusting inconsistent inbound quota configuration for network `%s', is %llu must be at least %llu\n"),
2845 GNUNET_NT_to_string (mlp->pv.quota_index[c]),
2846 mlp->pv.quota_in[c],
2847 (n_min * b_min));
2848 mlp->pv.quota_in[c] = (n_min * b_min);
2849 }
2850 /* Check if bandwidth is too big to make problem solvable */
2851 if (mlp->pv.BIG_M < mlp->pv.quota_out[c])
2852 {
2853 LOG (GNUNET_ERROR_TYPE_INFO,
2854 _ (
2855 "Adjusting outbound quota configuration for network `%s'from %llu to %.0f\n"),
2856 GNUNET_NT_to_string (mlp->pv.quota_index[c]),
2857 mlp->pv.quota_out[c],
2858 mlp->pv.BIG_M);
2859 mlp->pv.quota_out[c] = mlp->pv.BIG_M;
2860 }
2861 if (mlp->pv.BIG_M < mlp->pv.quota_in[c])
2862 {
2863 LOG (GNUNET_ERROR_TYPE_INFO,
2864 _ (
2865 "Adjusting inbound quota configuration for network `%s' from %llu to %.0f\n"),
2866 GNUNET_NT_to_string (mlp->pv.quota_index[c]),
2867 mlp->pv.quota_in[c],
2868 mlp->pv.BIG_M);
2869 mlp->pv.quota_in[c] = mlp->pv.BIG_M;
2870 }
2871 }
2872 mlp->env = env;
2873 sf.cls = mlp;
2874 sf.s_add = &GAS_mlp_address_add;
2875 sf.s_address_update_property = &GAS_mlp_address_property_changed;
2876 sf.s_get = &GAS_mlp_get_preferred_address;
2877 sf.s_get_stop = &GAS_mlp_stop_get_preferred_address;
2878 sf.s_pref = &GAS_mlp_address_change_preference;
2879 sf.s_feedback = &GAS_mlp_address_preference_feedback;
2880 sf.s_del = &GAS_mlp_address_delete;
2881 sf.s_bulk_start = &GAS_mlp_bulk_start;
2882 sf.s_bulk_stop = &GAS_mlp_bulk_stop;
2883
2884 /* Setting MLP Input variables */
2885 mlp->pv.b_min = b_min;
2886 mlp->pv.n_min = n_min;
2887 mlp->pv.m_q = RQ_QUALITY_METRIC_COUNT;
2888 mlp->stat_mlp_prob_changed = GNUNET_NO;
2889 mlp->stat_mlp_prob_updated = GNUNET_NO;
2890 mlp->opt_mlp_auto_solve = GNUNET_YES;
2891 mlp->requested_peers = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
2892 mlp->stat_bulk_requests = 0;
2893 mlp->stat_bulk_lock = 0;
2894
2895 /* Setup GLPK */
2896 /* Redirect GLPK output to GNUnet logging */
2897 glp_term_hook (&mlp_term_hook, (void *) mlp);
2898
2899 /* Init LP solving parameters */
2900 glp_init_smcp (&mlp->control_param_lp);
2901 mlp->control_param_lp.msg_lev = GLP_MSG_OFF;
2902 if (GNUNET_YES == mlp->opt_dbg_glpk_verbose)
2903 mlp->control_param_lp.msg_lev = GLP_MSG_ALL;
2904
2905 mlp->control_param_lp.it_lim = max_iterations;
2906 mlp->control_param_lp.tm_lim = max_duration.rel_value_us / 1000LL;
2907
2908 /* Init MLP solving parameters */
2909 glp_init_iocp (&mlp->control_param_mlp);
2910 /* Setting callback function */
2911 mlp->control_param_mlp.cb_func = &mlp_branch_and_cut_cb;
2912 mlp->control_param_mlp.cb_info = mlp;
2913 mlp->control_param_mlp.msg_lev = GLP_MSG_OFF;
2914 mlp->control_param_mlp.mip_gap = mlp->pv.mip_gap;
2915 if (GNUNET_YES == mlp->opt_dbg_glpk_verbose)
2916 mlp->control_param_mlp.msg_lev = GLP_MSG_ALL;
2917 mlp->control_param_mlp.tm_lim = max_duration.rel_value_us / 1000LL;
2918
2919 LOG (GNUNET_ERROR_TYPE_DEBUG, "solver ready\n");
2920
2921 return &sf;
2922}
2923
2924/* end of plugin_ats_mlp.c */
diff --git a/src/ats/plugin_ats_ril.c b/src/ats/plugin_ats_ril.c
deleted file mode 100644
index 7be3cb0a1..000000000
--- a/src/ats/plugin_ats_ril.c
+++ /dev/null
@@ -1,2997 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file ats/plugin_ats_ril.c
23 * @brief ATS reinforcement learning solver
24 * @author Fabian Oehlmann
25 * @author Matthias Wachs
26 */
27#include "platform.h"
28#include <float.h>
29#include <math.h>
30#include "gnunet_ats_plugin.h"
31#include "gnunet-service-ats_addresses.h"
32
33
34
35#define LOG(kind, ...) GNUNET_log_from (kind, "ats-ril", __VA_ARGS__)
36
37#define RIL_MIN_BW (5 * ntohl ( \
38 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT. \
39 value__))
40#define RIL_MAX_BW GNUNET_ATS_MaxBandwidth
41
42#define RIL_ACTION_INVALID -1
43#define RIL_INTERVAL_EXPONENT 10
44#define RIL_UTILITY_DELAY_MAX 1000
45
46#define RIL_DEFAULT_STEP_TIME_MIN GNUNET_TIME_relative_multiply ( \
47 GNUNET_TIME_UNIT_MILLISECONDS, 200)
48#define RIL_DEFAULT_STEP_TIME_MAX GNUNET_TIME_relative_multiply ( \
49 GNUNET_TIME_UNIT_MILLISECONDS, 2000)
50#define RIL_DEFAULT_ALGORITHM RIL_ALGO_SARSA
51#define RIL_DEFAULT_SELECT RIL_SELECT_SOFTMAX
52#define RIL_DEFAULT_WELFARE RIL_WELFARE_NASH
53#define RIL_DEFAULT_DISCOUNT_BETA 0.6
54#define RIL_DEFAULT_DISCOUNT_GAMMA 0.5
55#define RIL_DEFAULT_GRADIENT_STEP_SIZE 0.01
56#define RIL_DEFAULT_TRACE_DECAY 0.5
57#define RIL_DEFAULT_EXPLORE_RATIO 1
58#define RIL_DEFAULT_EXPLORE_DECAY 0.95
59#define RIL_DEFAULT_RBF_DIVISOR 50
60#define RIL_DEFAULT_TEMPERATURE 0.1
61#define RIL_DEFAULT_TEMPERATURE_DECAY 1
62
63#define RIL_INC_DEC_STEP_SIZE 1
64#define RIL_NOP_DECAY 0.5
65
66/**
67 * ATS reinforcement learning solver
68 *
69 * General description
70 */
71
72/**
73 * The actions, how an agent can manipulate the current assignment. I.e. how the bandwidth can be
74 * changed for the currently chosen address. Not depicted in the enum are the actions of switching
75 * to a particular address. The action of switching to address with index i is depicted by the
76 * number (RIL_ACTION_TYPE_NUM + i).
77 */
78enum RIL_Action_Type
79{
80 RIL_ACTION_NOTHING = 0,
81 RIL_ACTION_BW_IN_DBL = -2, // TODO? Potentially add more actions
82 RIL_ACTION_BW_IN_HLV = -3,
83 RIL_ACTION_BW_IN_INC = 1,
84 RIL_ACTION_BW_IN_DEC = 2,
85 RIL_ACTION_BW_OUT_DBL = -4,
86 RIL_ACTION_BW_OUT_HLV = -5,
87 RIL_ACTION_BW_OUT_INC = 3,
88 RIL_ACTION_BW_OUT_DEC = 4,
89 RIL_ACTION_TYPE_NUM = 5
90};
91
92enum RIL_Algorithm
93{
94 RIL_ALGO_SARSA = 0,
95 RIL_ALGO_Q = 1
96};
97
98enum RIL_Select
99{
100 RIL_SELECT_SOFTMAX = 0,
101 RIL_SELECT_EGREEDY = 1
102};
103
104enum RIL_Welfare
105{
106 RIL_WELFARE_NASH,
107 RIL_WELFARE_EGALITARIAN
108};
109
110enum RIL_E_Modification
111{
112 RIL_E_DECAY,
113 RIL_E_ZERO,
114 RIL_E_ACCUMULATE,
115 RIL_E_REPLACE
116};
117
118/**
119 * Global learning parameters
120 */
121struct RIL_Learning_Parameters
122{
123 /**
124 * The TD-algorithm to use
125 */
126 enum RIL_Algorithm algorithm;
127
128 /**
129 * Gradient-descent step-size
130 */
131 double alpha;
132
133 /**
134 * Learning discount variable in the TD-update for semi-MDPs
135 */
136 double beta;
137
138 /**
139 * Learning discount factor in the TD-update for MDPs
140 */
141 double gamma;
142
143 /**
144 * Trace-decay factor for eligibility traces
145 */
146 double lambda;
147
148 /**
149 * Whether to accumulate or replace eligibility traces
150 */
151 enum RIL_E_Modification eligibility_trace_mode;
152
153 /**
154 * Initial softmax action-selection temperature
155 */
156 double temperature_init;
157
158 /**
159 * Softmax action-selection temperature
160 */
161 double temperature;
162
163 /**
164 * Decay factor of the temperature value
165 */
166 double temperature_decay;
167
168 /**
169 * Which measure of social welfare should be used
170 */
171 enum RIL_Welfare social_welfare;
172
173 /**
174 * State space divisor
175 */
176 unsigned long long rbf_divisor;
177
178 /**
179 * Action selection strategy;
180 */
181 enum RIL_Select select;
182
183 /**
184 * Initial exploration ratio value
185 */
186 double epsilon_init;
187
188 /**
189 * Ratio, with what probability an agent should explore in the e-greed policy
190 */
191 double epsilon;
192
193 /**
194 * Decay factor of the explore ratio
195 */
196 double epsilon_decay;
197
198 /**
199 * Minimal interval time between steps in milliseconds
200 */
201 struct GNUNET_TIME_Relative step_time_min;
202
203 /**
204 * Maximum interval time between steps in milliseconds
205 */
206 struct GNUNET_TIME_Relative step_time_max;
207};
208
209/**
210 * Wrapper for addresses to store them in agent's linked list
211 */
212struct RIL_Address_Wrapped
213{
214 /**
215 * Next in DLL
216 */
217 struct RIL_Address_Wrapped *next;
218
219 /**
220 * Previous in DLL
221 */
222 struct RIL_Address_Wrapped *prev;
223
224 /**
225 * The address
226 */
227 struct ATS_Address *address_naked;
228};
229
230
231struct RIL_Peer_Agent
232{
233 /**
234 * Next agent in solver's linked list
235 */
236 struct RIL_Peer_Agent *next;
237
238 /**
239 * Previous agent in solver's linked list
240 */
241 struct RIL_Peer_Agent *prev;
242
243 /**
244 * Environment handle
245 */
246 struct GAS_RIL_Handle *envi;
247
248 /**
249 * Peer ID
250 */
251 struct GNUNET_PeerIdentity peer;
252
253 /**
254 * Whether the agent is active or not
255 */
256 int is_active;
257
258 /**
259 * Number of performed time-steps
260 */
261 unsigned long long step_count;
262
263 /**
264 * Experience matrix W
265 */
266 double **W;
267
268 /**
269 * Number of rows of W / Number of state-vector features
270 */
271 unsigned int m;
272
273 /**
274 * Number of columns of W / Number of actions
275 */
276 unsigned int n;
277
278 /**
279 * Last perceived state feature vector
280 */
281 double *s_old;
282
283 /**
284 * Last chosen action
285 */
286 int a_old;
287
288 /**
289 * Eligibility traces
290 */
291 double **E;
292
293 /**
294 * Whether to reset the eligibility traces to 0 after a Q-exploration step
295 */
296 int eligibility_reset;
297
298 /**
299 * Address in use
300 */
301 struct ATS_Address *address_inuse;
302
303 /**
304 * Head of addresses DLL
305 */
306 struct RIL_Address_Wrapped *addresses_head;
307
308 /**
309 * Tail of addresses DLL
310 */
311 struct RIL_Address_Wrapped *addresses_tail;
312
313 /**
314 * Inbound bandwidth assigned by the agent
315 */
316 uint32_t bw_in;
317
318 /**
319 * Outbound bandwidth assigned by the agent
320 */
321 uint32_t bw_out;
322
323 /**
324 * Flag whether a suggestion has to be issued
325 */
326 int suggestion_issue;
327
328 /**
329 * The address which has to be issued
330 */
331 struct ATS_Address *suggestion_address;
332
333 /**
334 * The agent's last objective value
335 */
336 double objective_old;
337
338 /**
339 * NOP bonus
340 */
341 double nop_bonus;
342};
343
344struct RIL_Scope
345{
346 /**
347 * ATS network type
348 */
349 enum GNUNET_NetworkType type;
350
351 /**
352 * Total available inbound bandwidth
353 */
354 uint32_t bw_in_available;
355
356 /**
357 * Bandwidth inbound assigned in network after last step
358 */
359 uint32_t bw_in_assigned;
360
361 /**
362 * Bandwidth inbound actually utilized in the network
363 */
364 uint32_t bw_in_utilized;
365
366 /**
367 * Total available outbound bandwidth
368 */
369 uint32_t bw_out_available;
370
371 /**
372 * Bandwidth outbound assigned in network after last step
373 */
374 unsigned long long bw_out_assigned;
375
376 /**
377 * Bandwidth outbound actually utilized in the network
378 */
379 unsigned long long bw_out_utilized;
380
381 /**
382 * Number of active agents in scope
383 */
384 unsigned int active_agent_count;
385
386 /**
387 * The social welfare achieved in the scope
388 */
389 double social_welfare;
390};
391
392/**
393 * A handle for the reinforcement learning solver
394 */
395struct GAS_RIL_Handle
396{
397 /**
398 * The solver-plugin environment of the solver-plugin API
399 */
400 struct GNUNET_ATS_PluginEnvironment *env;
401
402 /**
403 * Number of performed steps
404 */
405 unsigned long long step_count;
406
407 /**
408 * Timestamp for the last time-step
409 */
410 struct GNUNET_TIME_Absolute step_time_last;
411
412 /**
413 * Task identifier of the next time-step to be executed
414 */
415 struct GNUNET_SCHEDULER_Task *step_next_task_id;
416
417 /**
418 * Variable discount factor, dependent on time between steps
419 */
420 double global_discount_variable;
421
422 /**
423 * Integrated variable discount factor, dependent on time between steps
424 */
425 double global_discount_integrated;
426
427 /**
428 * Lock for bulk operations
429 */
430 int bulk_lock;
431
432 /**
433 * Number of changes during a lock
434 */
435 int bulk_changes;
436
437 /**
438 * Learning parameters
439 */
440 struct RIL_Learning_Parameters parameters;
441
442 /**
443 * Array of networks with global assignment state
444 */
445 struct RIL_Scope *network_entries;
446
447 /**
448 * Networks count
449 */
450 unsigned int networks_count;
451
452 /**
453 * List of active peer-agents
454 */
455 struct RIL_Peer_Agent *agents_head;
456 struct RIL_Peer_Agent *agents_tail;
457
458 /**
459 * Shutdown
460 */
461 int done;
462
463 /**
464 * Simulate steps, i.e. schedule steps immediately
465 */
466 unsigned long long simulate;
467};
468
469/*
470 * "Private" functions
471 * ---------------------------
472 */
473
474/**
475 * Estimate the current action-value for state s and action a
476 *
477 * @param agent agent performing the estimation
478 * @param state s
479 * @param action a
480 * @return estimation value
481 */
482static double
483agent_q (struct RIL_Peer_Agent *agent,
484 const double *state,
485 int action)
486{
487 unsigned int i;
488 double result = 0.0;
489
490 for (i = 0; i < agent->m; i++)
491 result += state[i] * agent->W[action][i];
492
493 /* prevent crashes if learning diverges */
494 if (isnan (result))
495 return isnan (result) * UINT32_MAX;
496 if (isinf (result))
497 return isinf (result) * UINT32_MAX;
498 return result;
499}
500
501
502/**
503 * Get the index of the address in the agent's list.
504 *
505 * @param agent agent handle
506 * @param address address handle
507 * @return the index, starting with zero
508 */
509static int
510agent_address_get_index (struct RIL_Peer_Agent *agent, struct
511 ATS_Address *address)
512{
513 int i;
514 struct RIL_Address_Wrapped *cur;
515
516 i = -1;
517 for (cur = agent->addresses_head; NULL != cur; cur = cur->next)
518 {
519 i++;
520 if (cur->address_naked == address)
521 return i;
522 }
523 return i;
524}
525
526
527/**
528 * Gets the wrapped address from the agent's list
529 *
530 * @param agent agent handle
531 * @param address address handle
532 * @return wrapped address
533 */
534static struct RIL_Address_Wrapped *
535agent_address_get_wrapped (struct RIL_Peer_Agent *agent, struct
536 ATS_Address *address)
537{
538 struct RIL_Address_Wrapped *cur;
539
540 for (cur = agent->addresses_head; NULL != cur; cur = cur->next)
541 if (cur->address_naked == address)
542 return cur;
543 return NULL;
544}
545
546
547static int
548agent_action_is_possible (struct RIL_Peer_Agent *agent, int action)
549{
550 int address_index;
551
552 switch (action)
553 {
554 case RIL_ACTION_NOTHING:
555 return GNUNET_YES;
556 break;
557
558 case RIL_ACTION_BW_IN_INC:
559 case RIL_ACTION_BW_IN_DBL:
560 if (agent->bw_in >= RIL_MAX_BW)
561 return GNUNET_NO;
562 else
563 return GNUNET_YES;
564 break;
565
566 case RIL_ACTION_BW_IN_DEC:
567 case RIL_ACTION_BW_IN_HLV:
568 if (agent->bw_in <= 0)
569 return GNUNET_NO;
570 else
571 return GNUNET_YES;
572 break;
573
574 case RIL_ACTION_BW_OUT_INC:
575 case RIL_ACTION_BW_OUT_DBL:
576 if (agent->bw_out >= RIL_MAX_BW)
577 return GNUNET_NO;
578 else
579 return GNUNET_YES;
580 break;
581
582 case RIL_ACTION_BW_OUT_DEC:
583 case RIL_ACTION_BW_OUT_HLV:
584 if (agent->bw_out <= 0)
585 return GNUNET_NO;
586 else
587 return GNUNET_YES;
588 break;
589
590 default:
591 if ((action >= RIL_ACTION_TYPE_NUM) && (action < agent->n)) // switch address action
592 {
593 address_index = action - RIL_ACTION_TYPE_NUM;
594
595 GNUNET_assert (address_index >= 0);
596 GNUNET_assert (
597 address_index <= agent_address_get_index (agent,
598 agent->addresses_tail->
599 address_naked));
600
601 if ((agent_address_get_index (agent, agent->address_inuse) ==
602 address_index) ||
603 agent->address_inuse->active)
604 return GNUNET_NO;
605 else
606 return GNUNET_YES;
607 break;
608 }
609 // error - action does not exist
610 GNUNET_assert (GNUNET_NO);
611 }
612}
613
614
615/**
616 * Gets the action, with the maximal estimated Q-value (i.e. the one currently estimated to bring the
617 * most reward in the future)
618 *
619 * @param agent agent performing the calculation
620 * @param state the state from which to take the action
621 * @return the action promising most future reward
622 */
623static int
624agent_get_action_max (struct RIL_Peer_Agent *agent, double *state)
625{
626 int i;
627 int max_i = RIL_ACTION_INVALID;
628 double cur_q;
629 double max_q = -DBL_MAX;
630
631 for (i = 0; i < agent->n; i++)
632 {
633 if (agent_action_is_possible (agent, i))
634 {
635 cur_q = agent_q (agent, state, i);
636 if (cur_q > max_q)
637 {
638 max_q = cur_q;
639 max_i = i;
640 }
641 }
642 }
643
644 GNUNET_assert (RIL_ACTION_INVALID != max_i);
645
646 return max_i;
647}
648
649/**
650 * Chooses a random action from the set of possible ones
651 *
652 * @param agent the agent performing the action
653 * @return the action index
654 */
655static int
656agent_get_action_random (struct RIL_Peer_Agent *agent)
657{
658 int i;
659 int is_possible[agent->n];
660 int sum = 0;
661 int r;
662
663 for (i = 0; i < agent->n; i++)
664 {
665 if (agent_action_is_possible (agent, i))
666 {
667 is_possible[i] = GNUNET_YES;
668 sum++;
669 }
670 else
671 {
672 is_possible[i] = GNUNET_NO;
673 }
674 }
675
676 r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, sum);
677
678 sum = -1;
679 for (i = 0; i < agent->n; i++)
680 {
681 if (is_possible[i])
682 {
683 sum++;
684 if (sum == r)
685 return i;
686 }
687 }
688
689 GNUNET_assert (GNUNET_NO);
690 return RIL_ACTION_INVALID;
691}
692
693
694/**
695 * Updates the weights (i.e. coefficients) of the weight vector in matrix W for action a
696 *
697 * @param agent the agent performing the update
698 * @param reward the reward received for the last action
699 * @param s_next the new state, the last step got the agent into
700 * @param a_prime the new
701 */
702static void
703agent_update (struct RIL_Peer_Agent *agent, double reward, double *s_next, int
704 a_prime)
705{
706 int i;
707 int k;
708 double delta;
709 double **theta = agent->W;
710
711 delta = agent->envi->global_discount_integrated * reward; // reward
712 delta += agent->envi->global_discount_variable * agent_q (agent, s_next,
713 a_prime); // discounted future value
714 delta -= agent_q (agent, agent->s_old, agent->a_old); // one step
715
716// LOG(GNUNET_ERROR_TYPE_INFO, "update() Step# %llu Q(s,a): %f a: %f r: %f y: %f Q(s+1,a+1) = %f delta: %f\n",
717// agent->step_count,
718// agent_q (agent, agent->s_old, agent->a_old),
719// agent->envi->parameters.alpha,
720// reward,
721// agent->envi->global_discount_variable,
722// agent_q (agent, s_next, a_prime),
723// delta);
724
725 for (k = 0; k < agent->n; k++)
726 {
727 for (i = 0; i < agent->m; i++)
728 {
729 // LOG(GNUNET_ERROR_TYPE_INFO, "alpha = %f delta = %f e[%d] = %f\n",
730 // agent->envi->parameters.alpha,
731 // delta,
732 // i,
733 // agent->e[i]);
734 theta[k][i] += agent->envi->parameters.alpha * delta * agent->E[k][i];
735 }
736 }
737}
738
739
740/**
741 * Changes the eligibility trace vector e in various manners:
742 * #RIL_E_ACCUMULATE - adds @a feature to each component as in accumulating eligibility traces
743 * #RIL_E_REPLACE - resets each component to @a feature as in replacing traces
744 * #RIL_E_DECAY - multiplies e with discount factor and lambda as in the update rule
745 * #RIL_E_ZERO - sets e to 0 as in Watkin's Q-learning algorithm when exploring and when initializing
746 *
747 * @param agent the agent handle
748 * @param mod the kind of modification
749 * @param feature the feature vector
750 * @param action the action to take
751 */
752static void
753agent_modify_eligibility (struct RIL_Peer_Agent *agent,
754 enum RIL_E_Modification mod,
755 double *feature,
756 int action)
757{
758 int i;
759 int k;
760
761 for (i = 0; i < agent->m; i++)
762 {
763 switch (mod)
764 {
765 case RIL_E_ACCUMULATE:
766 agent->E[action][i] += feature[i];
767 break;
768
769 case RIL_E_REPLACE:
770 agent->E[action][i] = agent->E[action][i] > feature[i] ?
771 agent->E[action][i] : feature[i];
772 break;
773
774 case RIL_E_DECAY:
775 for (k = 0; k < agent->n; k++)
776 {
777 agent->E[k][i] *= agent->envi->global_discount_variable
778 * agent->envi->parameters.lambda;
779 }
780 break;
781
782 case RIL_E_ZERO:
783 for (k = 0; k < agent->n; k++)
784 {
785 agent->E[k][i] = 0;
786 }
787 break;
788 }
789 }
790}
791
792/**
793 * Informs the environment about the status of the solver
794 *
795 * @param solver
796 * @param op
797 * @param stat
798 */
799static void
800ril_inform (struct GAS_RIL_Handle *solver,
801 enum GAS_Solver_Operation op,
802 enum GAS_Solver_Status stat)
803{
804 solver->env->info_cb (solver->env->cls,
805 op,
806 stat,
807 GAS_INFO_NONE);
808}
809
810/**
811 * Calculates the maximum bandwidth an agent can assign in a network scope
812 *
813 * @param net
814 */
815static unsigned long long
816ril_get_max_bw (struct RIL_Scope *net)
817{
818 return GNUNET_MIN (2 * GNUNET_MAX (net->bw_in_available,
819 net->bw_out_available),
820 GNUNET_ATS_MaxBandwidth);
821}
822
823/**
824 * Changes the active assignment suggestion of the handler and invokes the bw_changed callback to
825 * notify ATS of its new decision
826 *
827 * @param solver solver handle
828 * @param agent agent handle
829 * @param new_address the address which is to be used
830 * @param new_bw_in the new amount of inbound bandwidth set for this address
831 * @param new_bw_out the new amount of outbound bandwidth set for this address
832 * @param silent disables invocation of the bw_changed callback, if #GNUNET_YES
833 */
834static void
835envi_set_active_suggestion (struct GAS_RIL_Handle *solver,
836 struct RIL_Peer_Agent *agent,
837 struct ATS_Address *new_address,
838 unsigned long long new_bw_in,
839 unsigned long long new_bw_out,
840 int silent)
841{
842 int notify = GNUNET_NO;
843
844 LOG (GNUNET_ERROR_TYPE_DEBUG,
845 " set_active_suggestion() for peer '%s'\n",
846 GNUNET_i2s (&agent->peer));
847
848 // address change
849 if (agent->address_inuse != new_address)
850 {
851 if (NULL != agent->address_inuse)
852 {
853 agent->address_inuse->active = GNUNET_NO;
854 agent->address_inuse->assigned_bw_in = 0;
855 agent->address_inuse->assigned_bw_out = 0;
856 }
857 if (NULL != new_address)
858 {
859 LOG (GNUNET_ERROR_TYPE_DEBUG, " set address active: %s\n",
860 agent->is_active ? "yes" : "no");
861 new_address->active = agent->is_active;
862 new_address->assigned_bw_in = agent->bw_in;
863 new_address->assigned_bw_out = agent->bw_out;
864 }
865 notify |= GNUNET_YES;
866 }
867
868 if (new_address)
869 {
870 // activity change
871 if (new_address->active != agent->is_active)
872 {
873 new_address->active = agent->is_active;
874 notify |= GNUNET_YES;
875 }
876
877 // bw change
878 if (agent->bw_in != new_bw_in)
879 {
880 agent->bw_in = new_bw_in;
881 new_address->assigned_bw_in = new_bw_in;
882 notify |= GNUNET_YES;
883 }
884 if (agent->bw_out != new_bw_out)
885 {
886 agent->bw_out = new_bw_out;
887 new_address->assigned_bw_out = new_bw_out;
888 notify |= GNUNET_YES;
889 }
890 }
891
892 if (notify && agent->is_active && (GNUNET_NO == silent))
893 {
894 if (new_address)
895 {
896 LOG (GNUNET_ERROR_TYPE_DEBUG,
897 " envi_set_active_suggestion() notify\n");
898 agent->suggestion_issue = GNUNET_YES;
899 agent->suggestion_address = new_address;
900 }
901 else if (agent->address_inuse)
902 {
903 /* disconnect case, no new address */
904 GNUNET_assert (0 == agent->address_inuse->assigned_bw_in);
905 GNUNET_assert (0 == agent->address_inuse->assigned_bw_out);
906 agent->bw_in = 0;
907 agent->bw_out = 0;
908
909 agent->suggestion_issue = GNUNET_YES;
910 agent->suggestion_address = agent->address_inuse;
911 }
912 }
913 agent->address_inuse = new_address;
914}
915
916
917/**
918 * Allocates a state vector and fills it with the features present
919 * @param solver the solver handle
920 * @param agent the agent handle
921 * @return pointer to the state vector
922 */
923static double *
924envi_get_state (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent)
925{
926 double *state;
927 double y[2];
928 double x[2];
929 double d[2];
930 double sigma;
931 double f;
932 int m;
933 int i;
934 int k;
935 unsigned long long max_bw;
936
937 state = GNUNET_malloc (sizeof(double) * agent->m);
938
939 max_bw = ril_get_max_bw ((struct
940 RIL_Scope *) agent->address_inuse->
941 solver_information);
942
943 y[0] = (double) agent->bw_out;
944 y[1] = (double) agent->bw_in;
945
946 m = agent_address_get_index (agent, agent->address_inuse)
947 * (solver->parameters.rbf_divisor + 1) * (solver->parameters.rbf_divisor
948 + 1);
949 for (i = 0; i <= solver->parameters.rbf_divisor; i++)
950 {
951 for (k = 0; k <= solver->parameters.rbf_divisor; k++)
952 {
953 x[0] = (double) i * (double) max_bw
954 / (double) solver->parameters.rbf_divisor;
955 x[1] = (double) k * (double) max_bw
956 / (double) solver->parameters.rbf_divisor;
957 d[0] = x[0] - y[0];
958 d[1] = x[1] - y[1];
959 sigma = (((double) max_bw / ((double) solver->parameters.rbf_divisor
960 + 1)) * 0.5);
961 f = exp (-((d[0] * d[0] + d[1] * d[1]) / (2 * sigma * sigma)));
962 state[m++] = f;
963 }
964 }
965
966 return state;
967}
968
969
970/**
971 * Returns the utility value of the connection an agent manages
972 *
973 * @param agent the agent in question
974 * @return the utility value
975 */
976static double
977agent_get_utility (struct RIL_Peer_Agent *agent)
978{
979 const double *preferences;
980 double delay_atsi;
981 double delay_norm;
982 double pref_match;
983
984 preferences = agent->envi->env->get_preferences (agent->envi->env->cls,
985 &agent->peer);
986
987 delay_atsi = agent->address_inuse->norm_delay.norm;
988 delay_norm = RIL_UTILITY_DELAY_MAX * exp (-delay_atsi * 0.00001);
989
990 pref_match = preferences[GNUNET_ATS_PREFERENCE_LATENCY] * delay_norm;
991 pref_match += preferences[GNUNET_ATS_PREFERENCE_BANDWIDTH]
992 * sqrt ((double) (agent->bw_in / RIL_MIN_BW)
993 * (double) (agent->bw_out / RIL_MIN_BW));
994 return pref_match;
995}
996
997/**
998 * Calculates the social welfare within a network scope according to what social
999 * welfare measure is set in the configuration.
1000 *
1001 * @param solver the solver handle
1002 * @param scope the network scope in question
1003 * @return the social welfare value
1004 */
1005static double
1006ril_network_get_social_welfare (struct GAS_RIL_Handle *solver, struct
1007 RIL_Scope *scope)
1008{
1009 struct RIL_Peer_Agent *cur;
1010 double result;
1011
1012 switch (solver->parameters.social_welfare)
1013 {
1014 case RIL_WELFARE_EGALITARIAN:
1015 result = DBL_MAX;
1016 for (cur = solver->agents_head; NULL != cur; cur = cur->next)
1017 {
1018 if (cur->is_active && cur->address_inuse &&
1019 (cur->address_inuse->solver_information == scope))
1020 {
1021 result = GNUNET_MIN (result, agent_get_utility (cur));
1022 }
1023 }
1024 return result;
1025
1026 case RIL_WELFARE_NASH:
1027 result = 0;
1028 for (cur = solver->agents_head; NULL != cur; cur = cur->next)
1029 {
1030 if (cur->is_active && cur->address_inuse &&
1031 (cur->address_inuse->solver_information == scope))
1032 {
1033 result *= pow (agent_get_utility (cur), 1.0
1034 / (double) scope->active_agent_count);
1035 }
1036 }
1037 return result;
1038 }
1039 GNUNET_assert (GNUNET_NO);
1040 return 1;
1041}
1042
1043static double
1044envi_get_penalty (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent)
1045{
1046 struct RIL_Scope *net;
1047 unsigned long long over_max;
1048 unsigned long long over_in = 0;
1049 unsigned long long over_out = 0;
1050
1051 net = agent->address_inuse->solver_information;
1052
1053 if (net->bw_in_utilized > net->bw_in_available)
1054 {
1055 over_in = net->bw_in_utilized - net->bw_in_available;
1056 if (RIL_ACTION_BW_IN_INC == agent->a_old)
1057 {
1058 /* increase quadratically */
1059 over_in *= over_in;
1060 }
1061 }
1062 if (net->bw_out_utilized > net->bw_out_available)
1063 {
1064 over_out = net->bw_out_utilized - net->bw_out_available;
1065 if (RIL_ACTION_BW_OUT_INC == agent->a_old)
1066 {
1067 /* increase quadratically */
1068 over_out *= over_out;
1069 }
1070 }
1071 over_max = (over_in + over_out) / (RIL_MIN_BW * RIL_MIN_BW);
1072
1073 return -1.0 * (double) over_max;
1074}
1075
1076/**
1077 * Gets the reward for the last performed step, which is calculated in equal
1078 * parts from the local (the peer specific) and the global (for all peers
1079 * identical) reward.
1080 *
1081 * @param solver the solver handle
1082 * @param agent the agent handle
1083 * @return the reward
1084 */
1085static double
1086envi_get_reward (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent)
1087{
1088 struct RIL_Scope *net;
1089 double objective;
1090 double delta;
1091 double steady;
1092 double penalty;
1093 double reward;
1094
1095 net = agent->address_inuse->solver_information;
1096
1097 penalty = envi_get_penalty (solver, agent);
1098 objective = (agent_get_utility (agent) + net->social_welfare) / 2;
1099 delta = objective - agent->objective_old;
1100 agent->objective_old = objective;
1101
1102 if ((delta != 0)&&(penalty == 0))
1103 {
1104 agent->nop_bonus = delta * RIL_NOP_DECAY;
1105 }
1106 else
1107 {
1108 agent->nop_bonus *= RIL_NOP_DECAY;
1109 }
1110
1111 steady = (RIL_ACTION_NOTHING == agent->a_old) ? agent->nop_bonus : 0;
1112
1113 reward = delta + steady;
1114 return reward + penalty;
1115}
1116
1117/**
1118 * Doubles the bandwidth for the active address
1119 *
1120 * @param solver solver handle
1121 * @param agent agent handle
1122 * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise the outbound bandwidth
1123 */
1124static void
1125envi_action_bw_double (struct GAS_RIL_Handle *solver,
1126 struct RIL_Peer_Agent *agent,
1127 int direction_in)
1128{
1129 unsigned long long new_bw;
1130 unsigned long long max_bw;
1131
1132 max_bw = ril_get_max_bw ((struct
1133 RIL_Scope *) agent->address_inuse->
1134 solver_information);
1135
1136 if (direction_in)
1137 {
1138 new_bw = agent->bw_in * 2;
1139 if ((new_bw < agent->bw_in) ||(new_bw > max_bw) )
1140 new_bw = max_bw;
1141 envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw,
1142 agent->bw_out, GNUNET_NO);
1143 }
1144 else
1145 {
1146 new_bw = agent->bw_out * 2;
1147 if ((new_bw < agent->bw_out) ||(new_bw > max_bw) )
1148 new_bw = max_bw;
1149 envi_set_active_suggestion (solver, agent, agent->address_inuse,
1150 agent->bw_in,
1151 new_bw, GNUNET_NO);
1152 }
1153}
1154
1155/**
1156 * Cuts the bandwidth for the active address in half. The least amount of bandwidth suggested, is
1157 * the minimum bandwidth for a peer, in order to not invoke a disconnect.
1158 *
1159 * @param solver solver handle
1160 * @param agent agent handle
1161 * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise change the outbound
1162 * bandwidth
1163 */
1164static void
1165envi_action_bw_halven (struct GAS_RIL_Handle *solver,
1166 struct RIL_Peer_Agent *agent,
1167 int direction_in)
1168{
1169 unsigned long long new_bw;
1170
1171 if (direction_in)
1172 {
1173 new_bw = agent->bw_in / 2;
1174 if ((new_bw <= 0) ||(new_bw > agent->bw_in) )
1175 new_bw = 0;
1176 envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw,
1177 agent->bw_out,
1178 GNUNET_NO);
1179 }
1180 else
1181 {
1182 new_bw = agent->bw_out / 2;
1183 if ((new_bw <= 0) ||(new_bw > agent->bw_out) )
1184 new_bw = 0;
1185 envi_set_active_suggestion (solver, agent, agent->address_inuse,
1186 agent->bw_in, new_bw,
1187 GNUNET_NO);
1188 }
1189}
1190
1191/**
1192 * Increases the bandwidth by 5 times the minimum bandwidth for the active address.
1193 *
1194 * @param solver solver handle
1195 * @param agent agent handle
1196 * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise change the outbound
1197 * bandwidth
1198 */
1199static void
1200envi_action_bw_inc (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent,
1201 int direction_in)
1202{
1203 unsigned long long new_bw;
1204 unsigned long long max_bw;
1205
1206 max_bw = ril_get_max_bw ((struct
1207 RIL_Scope *) agent->address_inuse->
1208 solver_information);
1209
1210 if (direction_in)
1211 {
1212 new_bw = agent->bw_in + (RIL_INC_DEC_STEP_SIZE * RIL_MIN_BW);
1213 if ((new_bw < agent->bw_in) ||(new_bw > max_bw) )
1214 new_bw = max_bw;
1215 envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw,
1216 agent->bw_out, GNUNET_NO);
1217 }
1218 else
1219 {
1220 new_bw = agent->bw_out + (RIL_INC_DEC_STEP_SIZE * RIL_MIN_BW);
1221 if ((new_bw < agent->bw_out) ||(new_bw > max_bw) )
1222 new_bw = max_bw;
1223 envi_set_active_suggestion (solver, agent, agent->address_inuse,
1224 agent->bw_in,
1225 new_bw, GNUNET_NO);
1226 }
1227}
1228
1229/**
1230 * Decreases the bandwidth by 5 times the minimum bandwidth for the active address. The least amount
1231 * of bandwidth suggested, is the minimum bandwidth for a peer, in order to not invoke a disconnect.
1232 *
1233 * @param solver solver handle
1234 * @param agent agent handle
1235 * @param direction_in if GNUNET_YES, change inbound bandwidth, otherwise change the outbound
1236 * bandwidth
1237 */
1238static void
1239envi_action_bw_dec (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent,
1240 int direction_in)
1241{
1242 unsigned long long new_bw;
1243
1244 if (direction_in)
1245 {
1246 new_bw = agent->bw_in - (RIL_INC_DEC_STEP_SIZE * RIL_MIN_BW);
1247 if ((new_bw <= 0) ||(new_bw > agent->bw_in) )
1248 new_bw = 0;
1249 envi_set_active_suggestion (solver, agent, agent->address_inuse, new_bw,
1250 agent->bw_out,
1251 GNUNET_NO);
1252 }
1253 else
1254 {
1255 new_bw = agent->bw_out - (RIL_INC_DEC_STEP_SIZE * RIL_MIN_BW);
1256 if ((new_bw <= 0) ||(new_bw > agent->bw_out) )
1257 new_bw = 0;
1258 envi_set_active_suggestion (solver, agent, agent->address_inuse,
1259 agent->bw_in, new_bw,
1260 GNUNET_NO);
1261 }
1262}
1263
1264/**
1265 * Switches to the address given by its index
1266 *
1267 * @param solver solver handle
1268 * @param agent agent handle
1269 * @param address_index index of the address as it is saved in the agent's list, starting with zero
1270 */
1271static void
1272envi_action_address_switch (struct GAS_RIL_Handle *solver,
1273 struct RIL_Peer_Agent *agent,
1274 unsigned int address_index)
1275{
1276 struct RIL_Address_Wrapped *cur;
1277 int i = 0;
1278
1279 // cur = agent_address_get_wrapped(agent, agent->address_inuse);
1280
1281 for (cur = agent->addresses_head; NULL != cur; cur = cur->next)
1282 {
1283 if (i == address_index)
1284 {
1285 envi_set_active_suggestion (solver, agent, cur->address_naked,
1286 agent->bw_in, agent->bw_out,
1287 GNUNET_NO);
1288 return;
1289 }
1290
1291 i++;
1292 }
1293
1294 // no address with address_index exists, in this case this action should not be callable
1295 GNUNET_assert (GNUNET_NO);
1296}
1297
1298/**
1299 * Puts the action into effect by calling the according function
1300 *
1301 * @param solver the solver handle
1302 * @param agent the action handle
1303 * @param action the action to perform by the solver
1304 */
1305static void
1306envi_do_action (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent, int
1307 action)
1308{
1309 int address_index;
1310
1311 switch (action)
1312 {
1313 case RIL_ACTION_NOTHING:
1314 break;
1315
1316 case RIL_ACTION_BW_IN_DBL:
1317 envi_action_bw_double (solver, agent, GNUNET_YES);
1318 break;
1319
1320 case RIL_ACTION_BW_IN_HLV:
1321 envi_action_bw_halven (solver, agent, GNUNET_YES);
1322 break;
1323
1324 case RIL_ACTION_BW_IN_INC:
1325 envi_action_bw_inc (solver, agent, GNUNET_YES);
1326 break;
1327
1328 case RIL_ACTION_BW_IN_DEC:
1329 envi_action_bw_dec (solver, agent, GNUNET_YES);
1330 break;
1331
1332 case RIL_ACTION_BW_OUT_DBL:
1333 envi_action_bw_double (solver, agent, GNUNET_NO);
1334 break;
1335
1336 case RIL_ACTION_BW_OUT_HLV:
1337 envi_action_bw_halven (solver, agent, GNUNET_NO);
1338 break;
1339
1340 case RIL_ACTION_BW_OUT_INC:
1341 envi_action_bw_inc (solver, agent, GNUNET_NO);
1342 break;
1343
1344 case RIL_ACTION_BW_OUT_DEC:
1345 envi_action_bw_dec (solver, agent, GNUNET_NO);
1346 break;
1347
1348 default:
1349 if ((action >= RIL_ACTION_TYPE_NUM) && (action < agent->n)) // switch address action
1350 {
1351 address_index = action - RIL_ACTION_TYPE_NUM;
1352
1353 GNUNET_assert (address_index >= 0);
1354 GNUNET_assert (
1355 address_index <= agent_address_get_index (agent,
1356 agent->addresses_tail->
1357 address_naked));
1358
1359 envi_action_address_switch (solver, agent, address_index);
1360 break;
1361 }
1362 // error - action does not exist
1363 GNUNET_assert (GNUNET_NO);
1364 }
1365}
1366
1367/**
1368 * Selects the next action using the e-greedy strategy. I.e. with a probability
1369 * of (1-e) the action with the maximum expected return will be chosen
1370 * (=> exploitation) and with probability (e) a random action will be chosen.
1371 * In case the Q-learning rule is set, the function also resets the eligibility
1372 * traces in the exploration case (after Watkin's Q-learning).
1373 *
1374 * @param agent the agent selecting an action
1375 * @param state the current state-feature vector
1376 * @return the action index
1377 */
1378static int
1379agent_select_egreedy (struct RIL_Peer_Agent *agent, double *state)
1380{
1381 int action;
1382 double r = (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1383 UINT32_MAX)
1384 / (double) UINT32_MAX;
1385
1386 if (r < agent->envi->parameters.epsilon) // explore
1387 {
1388 action = agent_get_action_random (agent);
1389 if (RIL_ALGO_Q == agent->envi->parameters.algorithm)
1390 {
1391 agent->eligibility_reset = GNUNET_YES;
1392 }
1393 agent->envi->parameters.epsilon *= agent->envi->parameters.epsilon_decay;
1394 return action;
1395 }
1396 else // exploit
1397 {
1398 action = agent_get_action_max (agent, state);
1399 return action;
1400 }
1401}
1402
1403/**
1404 * Selects the next action with a probability corresponding to its value. The
1405 * probability is calculated using a Boltzmann distribution with a temperature
1406 * value. The higher the temperature, the more are the action selection
1407 * probabilities the same. With a temperature of 0, the selection is greedy,
1408 * i.e. always the action with the highest value is chosen.
1409 * @param agent
1410 * @param state
1411 * @return
1412 */
1413static int
1414agent_select_softmax (struct RIL_Peer_Agent *agent, double *state)
1415{
1416 int i;
1417 int a_max;
1418 double eqt[agent->n];
1419 double p[agent->n];
1420 double sum = 0;
1421 double r;
1422
1423 a_max = agent_get_action_max (agent, state);
1424
1425 for (i = 0; i < agent->n; i++)
1426 {
1427 if (agent_action_is_possible (agent, i))
1428 {
1429 eqt[i] = exp (agent_q (agent, state, i)
1430 / agent->envi->parameters.temperature);
1431 if (isinf (eqt[i]))
1432 eqt[i] = isinf (eqt[i]) * UINT32_MAX;
1433 sum += eqt[i];
1434 }
1435 }
1436 for (i = 0; i < agent->n; i++)
1437 {
1438 if (agent_action_is_possible (agent, i))
1439 {
1440 p[i] = eqt[i] / sum;
1441 }
1442 else
1443 {
1444 p[i] = 0;
1445 }
1446 }
1447 r = (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1448 UINT32_MAX) / (double) UINT32_MAX;
1449 sum = 0;
1450 for (i = 0; i < agent->n; i++)
1451 {
1452 if (sum + p[i] > r)
1453 {
1454 if (i != a_max)
1455 {
1456 if (RIL_ALGO_Q == agent->envi->parameters.algorithm)
1457 agent->eligibility_reset = GNUNET_YES;
1458 agent->envi->parameters.temperature *=
1459 agent->envi->parameters.temperature_decay;
1460 }
1461 return i;
1462 }
1463 sum += p[i];
1464 }
1465 GNUNET_assert (GNUNET_NO);
1466 return RIL_ACTION_INVALID;
1467}
1468
1469/**
1470 * Select the next action of an agent either according to the e-greedy strategy
1471 * or the softmax strategy.
1472 *
1473 * @param agent the agent in question
1474 * @param state the current state-feature vector
1475 * @return the action index
1476 */
1477static int
1478agent_select_action (struct RIL_Peer_Agent *agent, double *state)
1479{
1480 if (agent->envi->parameters.select == RIL_SELECT_EGREEDY)
1481 {
1482 return agent_select_egreedy (agent, state);
1483 }
1484 else
1485 {
1486 return agent_select_softmax (agent, state);
1487 }
1488}
1489
1490/**
1491 * Performs one step of the Markov Decision Process. Other than in the literature the step starts
1492 * after having done the last action a_old. It observes the new state s_next and the reward
1493 * received. Then the coefficient update is done according to the SARSA or Q-learning method. The
1494 * next action is put into effect.
1495 *
1496 * @param agent the agent performing the step
1497 */
1498static void
1499agent_step (struct RIL_Peer_Agent *agent)
1500{
1501 int a_next = RIL_ACTION_INVALID;
1502 int a_max;
1503 double *s_next;
1504 double reward;
1505
1506 LOG (GNUNET_ERROR_TYPE_DEBUG, " agent_step() Peer '%s', algorithm %s\n",
1507 GNUNET_i2s (&agent->peer),
1508 agent->envi->parameters.algorithm ? "Q" : "SARSA");
1509
1510 s_next = envi_get_state (agent->envi, agent);
1511 reward = envi_get_reward (agent->envi, agent);
1512
1513 if (agent->eligibility_reset)
1514 {
1515 agent_modify_eligibility (agent, RIL_E_ZERO, NULL, -1);
1516 agent->eligibility_reset = GNUNET_NO;
1517 }
1518 else
1519 {
1520 agent_modify_eligibility (agent, RIL_E_DECAY, NULL, -1);
1521 }
1522 if (RIL_ACTION_INVALID != agent->a_old)
1523 {
1524 agent_modify_eligibility (agent,
1525 agent->envi->parameters.eligibility_trace_mode,
1526 agent->s_old, agent->a_old);
1527 }
1528
1529 switch (agent->envi->parameters.algorithm)
1530 {
1531 case RIL_ALGO_SARSA:
1532 a_next = agent_select_action (agent, s_next);
1533 if (RIL_ACTION_INVALID != agent->a_old)
1534 {
1535 // updates weights with selected action (on-policy), if not first step
1536 agent_update (agent, reward, s_next, a_next);
1537 }
1538 break;
1539
1540 case RIL_ALGO_Q:
1541 a_max = agent_get_action_max (agent, s_next);
1542 if (RIL_ACTION_INVALID != agent->a_old)
1543 {
1544 // updates weights with best action, disregarding actually selected action (off-policy), if not first step
1545 agent_update (agent, reward, s_next, a_max);
1546 }
1547 a_next = agent_select_action (agent, s_next);
1548 break;
1549 }
1550
1551 GNUNET_assert (RIL_ACTION_INVALID != a_next);
1552
1553 LOG (GNUNET_ERROR_TYPE_DEBUG,
1554 "step() Step# %llu R: %f IN %llu OUT %llu A: %d\n",
1555 agent->step_count,
1556 reward,
1557 agent->bw_in / 1024,
1558 agent->bw_out / 1024,
1559 a_next);
1560
1561 envi_do_action (agent->envi, agent, a_next);
1562
1563 GNUNET_free (agent->s_old);
1564 agent->s_old = s_next;
1565 agent->a_old = a_next;
1566
1567 agent->step_count += 1;
1568}
1569
1570/**
1571 * Prototype of the ril_step() procedure
1572 *
1573 * @param solver the solver handle
1574 */
1575static void
1576ril_step (struct GAS_RIL_Handle *solver);
1577
1578
1579/**
1580 * Task for the scheduler, which performs one step and lets the solver know that
1581 * no further step is scheduled.
1582 *
1583 * @param cls the solver handle
1584 */
1585static void
1586ril_step_scheduler_task (void *cls)
1587{
1588 struct GAS_RIL_Handle *solver = cls;
1589
1590 solver->step_next_task_id = NULL;
1591 ril_step (solver);
1592}
1593
1594/**
1595 * Determines how much of the available bandwidth is assigned. If more is
1596 * assigned than available it returns 1. The function is used to determine the
1597 * step size of the adaptive stepping.
1598 *
1599 * @param solver the solver handle
1600 * @return the ratio
1601 */
1602static double
1603ril_get_used_resource_ratio (struct GAS_RIL_Handle *solver)
1604{
1605 int i;
1606 struct RIL_Scope net;
1607 unsigned long long sum_assigned = 0;
1608 unsigned long long sum_available = 0;
1609 double ratio;
1610
1611 for (i = 0; i < solver->networks_count; i++)
1612 {
1613 net = solver->network_entries[i];
1614 if (net.bw_in_assigned > 0) // only consider scopes where an address is actually active
1615 {
1616 sum_assigned += net.bw_in_utilized;
1617 sum_assigned += net.bw_out_utilized;
1618 sum_available += net.bw_in_available;
1619 sum_available += net.bw_out_available;
1620 }
1621 }
1622 if (sum_available > 0)
1623 {
1624 ratio = ((double) sum_assigned) / ((double) sum_available);
1625 }
1626 else
1627 {
1628 ratio = 0;
1629 }
1630
1631 return ratio > 1 ? 1 : ratio; // overutilization is possible, cap at 1
1632}
1633
1634/**
1635 * Lookup network struct by type
1636 *
1637 * @param s the solver handle
1638 * @param type the network type
1639 * @return the network struct
1640 */
1641static struct RIL_Scope *
1642ril_get_network (struct GAS_RIL_Handle *s, uint32_t type)
1643{
1644 int i;
1645
1646 for (i = 0; i < s->networks_count; i++)
1647 {
1648 if (s->network_entries[i].type == type)
1649 {
1650 return &s->network_entries[i];
1651 }
1652 }
1653 return NULL;
1654}
1655
1656/**
1657 * Determines whether more connections are allocated in a network scope, than
1658 * they would theoretically fit. This is used as a heuristic to determine,
1659 * whether a new connection can be allocated or not.
1660 *
1661 * @param solver the solver handle
1662 * @param network the network scope in question
1663 * @return GNUNET_YES if there are theoretically enough resources left
1664 */
1665static int
1666ril_network_is_not_full (struct GAS_RIL_Handle *solver, enum GNUNET_NetworkType
1667 network)
1668{
1669 struct RIL_Scope *net;
1670 struct RIL_Peer_Agent *agent;
1671 unsigned long long address_count = 0;
1672
1673 for (agent = solver->agents_head; NULL != agent; agent = agent->next)
1674 {
1675 if (agent->address_inuse && agent->is_active)
1676 {
1677 net = agent->address_inuse->solver_information;
1678 if (net->type == network)
1679 {
1680 address_count++;
1681 }
1682 }
1683 }
1684
1685 net = ril_get_network (solver, network);
1686 return (net->bw_in_available > RIL_MIN_BW * address_count) &&
1687 (net->bw_out_available > RIL_MIN_BW * address_count);
1688}
1689
1690/**
1691 * Unblocks an agent for which a connection request is there, that could not
1692 * be satisfied. Iterates over the addresses of the agent, if one of its
1693 * addresses can now be allocated in its scope the agent is unblocked,
1694 * otherwise it remains unchanged.
1695 *
1696 * @param solver the solver handle
1697 * @param agent the agent in question
1698 * @param silent
1699 */
1700static void
1701ril_try_unblock_agent (struct GAS_RIL_Handle *solver, struct
1702 RIL_Peer_Agent *agent, int silent)
1703{
1704 struct RIL_Address_Wrapped *addr_wrap;
1705 struct RIL_Scope *net;
1706 unsigned long long start_in;
1707 unsigned long long start_out;
1708
1709 for (addr_wrap = agent->addresses_head; NULL != addr_wrap; addr_wrap =
1710 addr_wrap->next)
1711 {
1712 net = addr_wrap->address_naked->solver_information;
1713 if (ril_network_is_not_full (solver, net->type))
1714 {
1715 if (NULL == agent->address_inuse)
1716 {
1717 start_in = net->bw_in_available < net->bw_in_utilized ?
1718 (net->bw_in_available - net->bw_in_utilized) / 2 :
1719 RIL_MIN_BW;
1720 start_out = net->bw_out_available < net->bw_out_utilized ?
1721 (net->bw_out_available - net->bw_out_utilized) / 2 :
1722 RIL_MIN_BW;
1723 envi_set_active_suggestion (solver, agent, addr_wrap->address_naked,
1724 start_in, start_out, silent);
1725 }
1726 return;
1727 }
1728 }
1729 agent->address_inuse = NULL;
1730}
1731
1732/**
1733 * Determines how much the reward needs to be discounted depending on the amount
1734 * of time, which has passed since the last time-step.
1735 *
1736 * @param solver the solver handle
1737 */
1738static void
1739ril_calculate_discount (struct GAS_RIL_Handle *solver)
1740{
1741 struct GNUNET_TIME_Absolute time_now;
1742 struct GNUNET_TIME_Relative time_delta;
1743 double tau;
1744
1745 // MDP case only for debugging purposes
1746 if (solver->simulate)
1747 {
1748 solver->global_discount_variable = solver->parameters.gamma;
1749 solver->global_discount_integrated = 1;
1750 return;
1751 }
1752
1753 // semi-MDP case
1754
1755 // calculate tau, i.e. how many real valued time units have passed, one time unit is one minimum time step
1756 time_now = GNUNET_TIME_absolute_get ();
1757 time_delta = GNUNET_TIME_absolute_get_difference (solver->step_time_last,
1758 time_now);
1759 solver->step_time_last = time_now;
1760 tau = (double) time_delta.rel_value_us
1761 / (double) solver->parameters.step_time_min.rel_value_us;
1762
1763 // calculate reward discounts (once per step for all agents)
1764 solver->global_discount_variable = pow (M_E, ((-1.0)
1765 * ((double) solver->parameters.
1766 beta) * tau));
1767 solver->global_discount_integrated = (1.0 - solver->global_discount_variable)
1768 / (double) solver->parameters.beta;
1769}
1770
1771/**
1772 * Count the number of active agents/connections in a network scope
1773 *
1774 * @param solver the solver handle
1775 * @param scope the network scope in question
1776 * @return the number of allocated connections
1777 */
1778static int
1779ril_network_count_active_agents (struct GAS_RIL_Handle *solver, struct
1780 RIL_Scope *scope)
1781{
1782 int c = 0;
1783 struct RIL_Peer_Agent *cur_agent;
1784
1785 for (cur_agent = solver->agents_head; NULL != cur_agent; cur_agent =
1786 cur_agent->next)
1787 {
1788 if (cur_agent->is_active && cur_agent->address_inuse &&
1789 (cur_agent->address_inuse->solver_information == scope))
1790 {
1791 c++;
1792 }
1793 }
1794 return c;
1795}
1796
1797/**
1798 * Calculates how much bandwidth is assigned in sum in a network scope, either
1799 * in the inbound or in the outbound direction.
1800 *
1801 * @param solver the solver handle
1802 * @param type the type of the network scope in question
1803 * @param direction_in GNUNET_YES if the inbound direction should be summed up,
1804 * otherwise the outbound direction will be summed up
1805 * @return the sum of the assigned bandwidths
1806 */
1807static unsigned long long
1808ril_network_get_assigned (struct GAS_RIL_Handle *solver, enum GNUNET_NetworkType
1809 type, int direction_in)
1810{
1811 struct RIL_Peer_Agent *cur;
1812 struct RIL_Scope *net;
1813 unsigned long long sum = 0;
1814
1815 for (cur = solver->agents_head; NULL != cur; cur = cur->next)
1816 {
1817 if (cur->is_active && cur->address_inuse)
1818 {
1819 net = cur->address_inuse->solver_information;
1820 if (net->type == type)
1821 {
1822 if (direction_in)
1823 sum += cur->bw_in;
1824 else
1825 sum += cur->bw_out;
1826 }
1827 }
1828 }
1829
1830 return sum;
1831}
1832
1833/**
1834 * Calculates how much bandwidth is actually utilized in sum in a network scope,
1835 * either in the inbound or in the outbound direction.
1836 *
1837 * @param solver the solver handle
1838 * @param type the type of the network scope in question
1839 * @param direction_in GNUNET_YES if the inbound direction should be summed up,
1840 * otherwise the outbound direction will be summed up
1841 * @return the sum of the utilized bandwidths (in bytes/second)
1842 */
1843static unsigned long long
1844ril_network_get_utilized (struct GAS_RIL_Handle *solver, enum GNUNET_NetworkType
1845 type, int direction_in)
1846{
1847 struct RIL_Peer_Agent *cur;
1848 struct RIL_Scope *net;
1849 unsigned long long sum = 0;
1850
1851 for (cur = solver->agents_head; NULL != cur; cur = cur->next)
1852 {
1853 if (cur->is_active && cur->address_inuse)
1854 {
1855 net = cur->address_inuse->solver_information;
1856 if (net->type == type)
1857 {
1858 if (direction_in)
1859 sum += cur->address_inuse->norm_utilization_in.norm;
1860 else
1861 sum += cur->address_inuse->norm_utilization_out.norm;
1862 }
1863 }
1864 }
1865
1866 return sum;
1867}
1868
1869/**
1870 * Retrieves the state of the network scope, so that its attributes are up-to-
1871 * date.
1872 *
1873 * @param solver the solver handle
1874 */
1875static void
1876ril_networks_update_state (struct GAS_RIL_Handle *solver)
1877{
1878 int c;
1879 struct RIL_Scope *net;
1880
1881 for (c = 0; c < solver->networks_count; c++)
1882 {
1883 net = &solver->network_entries[c];
1884 net->bw_in_assigned = ril_network_get_assigned (solver, net->type,
1885 GNUNET_YES);
1886 net->bw_in_utilized = ril_network_get_utilized (solver, net->type,
1887 GNUNET_YES);
1888 net->bw_out_assigned = ril_network_get_assigned (solver, net->type,
1889 GNUNET_NO);
1890 net->bw_out_utilized = ril_network_get_utilized (solver, net->type,
1891 GNUNET_NO);
1892 net->active_agent_count = ril_network_count_active_agents (solver, net);
1893 net->social_welfare = ril_network_get_social_welfare (solver, net);
1894 }
1895}
1896
1897/**
1898 * Schedules the next global step in an adaptive way. The more resources are
1899 * left, the earlier the next step is scheduled. This serves the reactivity of
1900 * the solver to changed inputs.
1901 *
1902 * @param solver the solver handle
1903 */
1904static void
1905ril_step_schedule_next (struct GAS_RIL_Handle *solver)
1906{
1907 double used_ratio;
1908 double factor;
1909 double y;
1910 double offset;
1911 struct GNUNET_TIME_Relative time_next;
1912
1913 used_ratio = ril_get_used_resource_ratio (solver);
1914
1915 GNUNET_assert (
1916 solver->parameters.step_time_min.rel_value_us
1917 <= solver->parameters.step_time_max.rel_value_us);
1918
1919 factor = (double) GNUNET_TIME_relative_subtract (
1920 solver->parameters.step_time_max,
1921 solver->parameters.
1922 step_time_min).rel_value_us;
1923 offset = (double) solver->parameters.step_time_min.rel_value_us;
1924 y = factor * pow (used_ratio, RIL_INTERVAL_EXPONENT) + offset;
1925
1926 GNUNET_assert (y <= (double) solver->parameters.step_time_max.rel_value_us);
1927 GNUNET_assert (y >= (double) solver->parameters.step_time_min.rel_value_us);
1928
1929 time_next = GNUNET_TIME_relative_saturating_multiply (
1930 GNUNET_TIME_UNIT_MICROSECONDS, (unsigned long long) y);
1931
1932// LOG (GNUNET_ERROR_TYPE_INFO, "ratio: %f, factor: %f, offset: %f, y: %f\n",
1933// used_ratio,
1934// factor,
1935// offset,
1936// y);
1937
1938 if (solver->simulate)
1939 {
1940 time_next = GNUNET_TIME_UNIT_ZERO;
1941 }
1942
1943 if ((NULL == solver->step_next_task_id) && (GNUNET_NO == solver->done))
1944 {
1945 solver->step_next_task_id = GNUNET_SCHEDULER_add_delayed (time_next,
1946 &
1947 ril_step_scheduler_task,
1948 solver);
1949 }
1950}
1951
1952/**
1953 * Triggers one step per agent
1954 *
1955 * @param solver
1956 */
1957static void
1958ril_step (struct GAS_RIL_Handle *solver)
1959{
1960 struct RIL_Peer_Agent *cur;
1961
1962 if (GNUNET_YES == solver->bulk_lock)
1963 {
1964 solver->bulk_changes++;
1965 return;
1966 }
1967
1968 ril_inform (solver, GAS_OP_SOLVE_START, GAS_STAT_SUCCESS);
1969
1970 LOG (GNUNET_ERROR_TYPE_DEBUG, " RIL step number %d\n", solver->step_count);
1971
1972 if (0 == solver->step_count)
1973 {
1974 solver->step_time_last = GNUNET_TIME_absolute_get ();
1975 }
1976
1977 ril_calculate_discount (solver);
1978 ril_networks_update_state (solver);
1979
1980 // trigger one step per active, unblocked agent
1981 for (cur = solver->agents_head; NULL != cur; cur = cur->next)
1982 {
1983 if (cur->is_active)
1984 {
1985 if (NULL == cur->address_inuse)
1986 {
1987 ril_try_unblock_agent (solver, cur, GNUNET_NO);
1988 }
1989 if (cur->address_inuse)
1990 {
1991 agent_step (cur);
1992 }
1993 }
1994 }
1995
1996 ril_networks_update_state (solver);
1997
1998 solver->step_count++;
1999 ril_step_schedule_next (solver);
2000
2001 ril_inform (solver, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS);
2002
2003 ril_inform (solver, GAS_OP_SOLVE_UPDATE_NOTIFICATION_START, GAS_STAT_SUCCESS);
2004 for (cur = solver->agents_head; NULL != cur; cur = cur->next)
2005 {
2006 if (cur->suggestion_issue)
2007 {
2008 solver->env->bandwidth_changed_cb (solver->env->cls,
2009 cur->suggestion_address);
2010 cur->suggestion_issue = GNUNET_NO;
2011 }
2012 }
2013 ril_inform (solver, GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP, GAS_STAT_SUCCESS);
2014}
2015
2016/**
2017 * Initializes the matrix W of parameter vectors theta with small random numbers.
2018 *
2019 * @param agent The respective agent
2020 */
2021static void
2022agent_w_init (struct RIL_Peer_Agent *agent)
2023{
2024 int i;
2025 int k;
2026
2027 for (i = 0; i < agent->n; i++)
2028 {
2029 for (k = 0; k < agent->m; k++)
2030 {
2031 agent->W[i][k] = agent->envi->parameters.alpha * (1.0 - 2.0
2032 * ((double)
2033 GNUNET_CRYPTO_random_u32 (
2034 GNUNET_CRYPTO_QUALITY_WEAK,
2035 UINT32_MAX)
2036 / (double) UINT32_MAX));
2037 }
2038 }
2039}
2040
2041/**
2042 * Initialize an agent without addresses and its knowledge base
2043 *
2044 * @param s ril solver
2045 * @param peer the one in question
2046 * @return handle to the new agent
2047 */
2048static struct RIL_Peer_Agent *
2049agent_init (void *s, const struct GNUNET_PeerIdentity *peer)
2050{
2051 int i;
2052 struct GAS_RIL_Handle *solver = s;
2053 struct RIL_Peer_Agent *agent = GNUNET_new (struct RIL_Peer_Agent);
2054
2055 agent->envi = solver;
2056 agent->peer = *peer;
2057 agent->step_count = 0;
2058 agent->is_active = GNUNET_NO;
2059 agent->bw_in = RIL_MIN_BW;
2060 agent->bw_out = RIL_MIN_BW;
2061 agent->suggestion_issue = GNUNET_NO;
2062 agent->n = RIL_ACTION_TYPE_NUM;
2063 agent->m = 0;
2064 agent->W = (double **) GNUNET_malloc (sizeof(double *) * agent->n);
2065 agent->E = (double **) GNUNET_malloc (sizeof(double *) * agent->n);
2066 for (i = 0; i < agent->n; i++)
2067 {
2068 agent->W[i] = (double *) GNUNET_malloc (sizeof(double) * agent->m);
2069 agent->E[i] = (double *) GNUNET_malloc (sizeof(double) * agent->m);
2070 }
2071 agent_w_init (agent);
2072 agent->eligibility_reset = GNUNET_NO;
2073 agent->a_old = RIL_ACTION_INVALID;
2074 agent->s_old = GNUNET_malloc (sizeof(double) * agent->m);
2075 agent->address_inuse = NULL;
2076 agent->objective_old = 0;
2077 agent->nop_bonus = 0;
2078
2079 return agent;
2080}
2081
2082/**
2083 * Deallocate agent
2084 *
2085 * @param solver the solver handle
2086 * @param agent the agent to retire
2087 */
2088static void
2089agent_die (struct GAS_RIL_Handle *solver, struct RIL_Peer_Agent *agent)
2090{
2091 int i;
2092
2093 for (i = 0; i < agent->n; i++)
2094 {
2095 GNUNET_free_non_null (agent->W[i]);
2096 GNUNET_free_non_null (agent->E[i]);
2097 }
2098 GNUNET_free_non_null (agent->W);
2099 GNUNET_free_non_null (agent->E);
2100 GNUNET_free_non_null (agent->s_old);
2101 GNUNET_free (agent);
2102}
2103
2104/**
2105 * Returns the agent for a peer
2106 *
2107 * @param solver the solver handle
2108 * @param peer the identity of the peer
2109 * @param create whether or not to create an agent, if none is allocated yet
2110 * @return the agent
2111 */
2112static struct RIL_Peer_Agent *
2113ril_get_agent (struct GAS_RIL_Handle *solver, const struct
2114 GNUNET_PeerIdentity *peer, int create)
2115{
2116 struct RIL_Peer_Agent *cur;
2117
2118 for (cur = solver->agents_head; NULL != cur; cur = cur->next)
2119 {
2120 if (0 == GNUNET_memcmp (peer, &cur->peer))
2121 {
2122 return cur;
2123 }
2124 }
2125
2126 if (create)
2127 {
2128 cur = agent_init (solver, peer);
2129 GNUNET_CONTAINER_DLL_insert_tail (solver->agents_head, solver->agents_tail,
2130 cur);
2131 return cur;
2132 }
2133 return NULL;
2134}
2135
2136/**
2137 * Determine whether at least the minimum bandwidth is set for the network. Otherwise the network is
2138 * considered inactive and not used. Addresses in an inactive network are ignored.
2139 *
2140 * @param solver solver handle
2141 * @param network the network type
2142 * @return whether or not the network is considered active
2143 */
2144static int
2145ril_network_is_active (struct GAS_RIL_Handle *solver, enum GNUNET_NetworkType
2146 network)
2147{
2148 struct RIL_Scope *net;
2149
2150 net = ril_get_network (solver, network);
2151 return net->bw_out_available >= RIL_MIN_BW;
2152}
2153
2154/**
2155 * Cuts a slice out of a vector of elements. This is used to decrease the size of the matrix storing
2156 * the reward function approximation. It copies the memory, which is not cut, to the new vector,
2157 * frees the memory of the old vector, and redirects the pointer to the new one.
2158 *
2159 * @param old pointer to the pointer to the first element of the vector
2160 * @param element_size byte size of the vector elements
2161 * @param hole_start the first element to cut out
2162 * @param hole_length the number of elements to cut out
2163 * @param old_length the length of the old vector
2164 */
2165static void
2166ril_cut_from_vector (void **old,
2167 size_t element_size,
2168 unsigned int hole_start,
2169 unsigned int hole_length,
2170 unsigned int old_length)
2171{
2172 char *tmpptr;
2173 char *oldptr = (char *) *old;
2174 size_t size;
2175 unsigned int bytes_before;
2176 unsigned int bytes_hole;
2177 unsigned int bytes_after;
2178
2179 GNUNET_assert (old_length >= hole_length);
2180 GNUNET_assert (old_length >= (hole_start + hole_length));
2181
2182 size = element_size * (old_length - hole_length);
2183
2184 bytes_before = element_size * hole_start;
2185 bytes_hole = element_size * hole_length;
2186 bytes_after = element_size * (old_length - hole_start - hole_length);
2187
2188 if (0 == size)
2189 {
2190 tmpptr = NULL;
2191 }
2192 else
2193 {
2194 tmpptr = GNUNET_malloc (size);
2195 GNUNET_memcpy (tmpptr, oldptr, bytes_before);
2196 GNUNET_memcpy (tmpptr + bytes_before, oldptr + (bytes_before + bytes_hole),
2197 bytes_after);
2198 }
2199 if (NULL != *old)
2200 {
2201 GNUNET_free (*old);
2202 }
2203 *old = (void *) tmpptr;
2204}
2205
2206/*
2207 * Solver API functions
2208 * ---------------------------
2209 */
2210
2211/**
2212 * Change relative preference for quality in solver
2213 *
2214 * @param solver the solver handle
2215 * @param peer the peer to change the preference for
2216 * @param kind the kind to change the preference
2217 * @param pref_rel the normalized preference value for this kind over all clients
2218 */
2219static void
2220GAS_ril_address_change_preference (void *solver,
2221 const struct GNUNET_PeerIdentity *peer,
2222 enum GNUNET_ATS_PreferenceKind kind,
2223 double pref_rel)
2224{
2225 LOG (GNUNET_ERROR_TYPE_DEBUG,
2226 "API_address_change_preference() Preference '%s' for peer '%s' changed to %.2f \n",
2227 GNUNET_ATS_print_preference_type (kind), GNUNET_i2s (peer), pref_rel);
2228
2229 struct GAS_RIL_Handle *s = solver;
2230
2231 s->parameters.temperature = s->parameters.temperature_init;
2232 s->parameters.epsilon = s->parameters.epsilon_init;
2233 ril_step (s);
2234}
2235
2236
2237/**
2238 * Add a new address for a peer to the solver
2239 *
2240 * The address is already contained in the addresses hashmap!
2241 *
2242 * @param solver the solver Handle
2243 * @param address the address to add
2244 * @param network network type of this address
2245 */
2246static void
2247GAS_ril_address_add (void *solver,
2248 struct ATS_Address *address,
2249 uint32_t network)
2250{
2251 struct GAS_RIL_Handle *s = solver;
2252 struct RIL_Peer_Agent *agent;
2253 struct RIL_Address_Wrapped *address_wrapped;
2254 struct RIL_Scope *net;
2255 unsigned int m_new;
2256 unsigned int m_old;
2257 unsigned int n_new;
2258 unsigned int n_old;
2259 int i;
2260 unsigned int zero;
2261
2262 LOG (GNUNET_ERROR_TYPE_DEBUG,
2263 "API_address_add()\n");
2264
2265 net = ril_get_network (s, network);
2266 address->solver_information = net;
2267
2268 if (! ril_network_is_active (s, network))
2269 {
2270 LOG (GNUNET_ERROR_TYPE_DEBUG,
2271 "API_address_add() Did not add %s address %s for peer '%s', network does not have enough bandwidth\n",
2272 address->plugin, address->addr, GNUNET_i2s (&address->peer));
2273 return;
2274 }
2275
2276 s->parameters.temperature = s->parameters.temperature_init;
2277 s->parameters.epsilon = s->parameters.epsilon_init;
2278
2279 agent = ril_get_agent (s, &address->peer, GNUNET_YES);
2280
2281 // add address
2282 address_wrapped = GNUNET_new (struct RIL_Address_Wrapped);
2283 address_wrapped->address_naked = address;
2284 GNUNET_CONTAINER_DLL_insert_tail (agent->addresses_head,
2285 agent->addresses_tail, address_wrapped);
2286
2287 // increase size of W
2288 m_new = agent->m + ((s->parameters.rbf_divisor + 1)
2289 * (s->parameters.rbf_divisor + 1));
2290 m_old = agent->m;
2291 n_new = agent->n + 1;
2292 n_old = agent->n;
2293
2294 GNUNET_array_grow (agent->W, agent->n, n_new);
2295 agent->n = n_old;
2296 GNUNET_array_grow (agent->E, agent->n, n_new);
2297 for (i = 0; i < n_new; i++)
2298 {
2299 if (i < n_old)
2300 {
2301 agent->m = m_old;
2302 GNUNET_array_grow (agent->W[i], agent->m, m_new);
2303 agent->m = m_old;
2304 GNUNET_array_grow (agent->E[i], agent->m, m_new);
2305 }
2306 else
2307 {
2308 zero = 0;
2309 GNUNET_array_grow (agent->W[i], zero, m_new);
2310 zero = 0;
2311 GNUNET_array_grow (agent->E[i], zero, m_new);
2312 }
2313 }
2314
2315 // increase size of old state vector
2316 agent->m = m_old;
2317 GNUNET_array_grow (agent->s_old, agent->m, m_new);
2318
2319 ril_try_unblock_agent (s, agent, GNUNET_NO);
2320
2321 ril_step (s);
2322
2323 LOG (GNUNET_ERROR_TYPE_DEBUG,
2324 "API_address_add() Added %s %s address %s for peer '%s'\n",
2325 address->active ? "active" : "inactive", address->plugin, address->addr,
2326 GNUNET_i2s (&address->peer));
2327}
2328
2329/**
2330 * Delete an address in the solver
2331 *
2332 * The address is not contained in the address hashmap anymore!
2333 *
2334 * @param solver the solver handle
2335 * @param address the address to remove
2336 */
2337static void
2338GAS_ril_address_delete (void *solver,
2339 struct ATS_Address *address)
2340{
2341 struct GAS_RIL_Handle *s = solver;
2342 struct RIL_Peer_Agent *agent;
2343 struct RIL_Address_Wrapped *address_wrapped;
2344 int address_index;
2345 unsigned int m_new;
2346 unsigned int n_new;
2347 int i;
2348 struct RIL_Scope *net;
2349
2350 LOG (GNUNET_ERROR_TYPE_DEBUG,
2351 "API_address_delete() Delete %s %s address %s for peer '%s'\n",
2352 address->active ? "active" : "inactive",
2353 address->plugin,
2354 address->addr,
2355 GNUNET_i2s (&address->peer));
2356
2357 agent = ril_get_agent (s, &address->peer, GNUNET_NO);
2358 if (NULL == agent)
2359 {
2360 net = address->solver_information;
2361 GNUNET_assert (! ril_network_is_active (s, net->type));
2362 LOG (GNUNET_ERROR_TYPE_DEBUG,
2363 "No agent allocated for peer yet, since address was in inactive network\n");
2364 return;
2365 }
2366
2367 s->parameters.temperature = s->parameters.temperature_init;
2368 s->parameters.epsilon = s->parameters.epsilon_init;
2369
2370 address_index = agent_address_get_index (agent, address);
2371 address_wrapped = agent_address_get_wrapped (agent, address);
2372
2373 if (NULL == address_wrapped)
2374 {
2375 net = address->solver_information;
2376 LOG (GNUNET_ERROR_TYPE_DEBUG,
2377 "Address not considered by agent, address was in inactive network\n");
2378 return;
2379 }
2380 GNUNET_CONTAINER_DLL_remove (agent->addresses_head,
2381 agent->addresses_tail,
2382 address_wrapped);
2383 GNUNET_free (address_wrapped);
2384
2385 // decrease W
2386 m_new = agent->m - ((s->parameters.rbf_divisor + 1)
2387 * (s->parameters.rbf_divisor + 1));
2388 n_new = agent->n - 1;
2389
2390 for (i = 0; i < agent->n; i++)
2391 {
2392 ril_cut_from_vector ((void **) &agent->W[i], sizeof(double),
2393 address_index * ((s->parameters.rbf_divisor + 1)
2394 * (s->parameters.rbf_divisor + 1)),
2395 ((s->parameters.rbf_divisor + 1)
2396 * (s->parameters.rbf_divisor + 1)), agent->m);
2397 ril_cut_from_vector ((void **) &agent->E[i], sizeof(double),
2398 address_index * ((s->parameters.rbf_divisor + 1)
2399 * (s->parameters.rbf_divisor + 1)),
2400 ((s->parameters.rbf_divisor + 1)
2401 * (s->parameters.rbf_divisor + 1)), agent->m);
2402 }
2403 GNUNET_free_non_null (agent->W[RIL_ACTION_TYPE_NUM + address_index]);
2404 GNUNET_free_non_null (agent->E[RIL_ACTION_TYPE_NUM + address_index]);
2405 ril_cut_from_vector ((void **) &agent->W, sizeof(double *),
2406 RIL_ACTION_TYPE_NUM + address_index,
2407 1, agent->n);
2408 ril_cut_from_vector ((void **) &agent->E, sizeof(double *),
2409 RIL_ACTION_TYPE_NUM + address_index,
2410 1, agent->n);
2411 // correct last action
2412 if (agent->a_old > (RIL_ACTION_TYPE_NUM + address_index))
2413 {
2414 agent->a_old -= 1;
2415 }
2416 else if (agent->a_old == (RIL_ACTION_TYPE_NUM + address_index))
2417 {
2418 agent->a_old = RIL_ACTION_INVALID;
2419 }
2420 // decrease old state vector
2421 ril_cut_from_vector ((void **) &agent->s_old, sizeof(double),
2422 address_index * ((s->parameters.rbf_divisor + 1)
2423 * (s->parameters.rbf_divisor + 1)),
2424 ((s->parameters.rbf_divisor + 1)
2425 * (s->parameters.rbf_divisor + 1)), agent->m);
2426 agent->m = m_new;
2427 agent->n = n_new;
2428
2429 if (agent->address_inuse == address)
2430 {
2431 if (NULL != agent->addresses_head) // if peer has an address left, use it
2432 {
2433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2434 "Active address died, suggesting alternative!\n");
2435 envi_set_active_suggestion (s,
2436 agent,
2437 agent->addresses_head->address_naked,
2438 agent->bw_in,
2439 agent->bw_out,
2440 GNUNET_YES);
2441 }
2442 else
2443 {
2444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2445 "Active address died, suggesting disconnect!\n");
2446 envi_set_active_suggestion (s, agent, NULL, 0, 0, GNUNET_NO);
2447 }
2448 }
2449 ril_step (solver);
2450 if (agent->suggestion_address == address)
2451 {
2452 agent->suggestion_issue = GNUNET_NO;
2453 agent->suggestion_address = NULL;
2454 }
2455 GNUNET_assert (agent->address_inuse != address);
2456}
2457
2458
2459/**
2460 * Update the properties of an address in the solver
2461 *
2462 * @param solver solver handle
2463 * @param address the address
2464 */
2465static void
2466GAS_ril_address_property_changed (void *solver,
2467 struct ATS_Address *address)
2468{
2469 struct GAS_RIL_Handle *s = solver;
2470
2471 LOG (GNUNET_ERROR_TYPE_DEBUG,
2472 "Properties for peer '%s' address changed\n",
2473 GNUNET_i2s (&address->peer));
2474 s->parameters.temperature = s->parameters.temperature_init;
2475 s->parameters.epsilon = s->parameters.epsilon_init;
2476 ril_step (s);
2477}
2478
2479
2480/**
2481 * Give feedback about the current assignment
2482 *
2483 * @param solver the solver handle
2484 * @param application the application
2485 * @param peer the peer to change the preference for
2486 * @param scope the time interval for this feedback: [now - scope .. now]
2487 * @param kind the kind to change the preference
2488 * @param score the score
2489 */
2490static void
2491GAS_ril_address_preference_feedback (void *solver,
2492 struct GNUNET_SERVICE_Client *application,
2493 const struct GNUNET_PeerIdentity *peer,
2494 const struct GNUNET_TIME_Relative scope,
2495 enum GNUNET_ATS_PreferenceKind kind,
2496 double score)
2497{
2498 LOG (GNUNET_ERROR_TYPE_DEBUG,
2499 "API_address_preference_feedback() Peer '%s' got a feedback of %+.3f from application %s for "
2500 "preference %s for %d seconds\n",
2501 GNUNET_i2s (peer),
2502 "UNKNOWN",
2503 GNUNET_ATS_print_preference_type (kind),
2504 scope.rel_value_us / 1000000);
2505}
2506
2507
2508/**
2509 * Start a bulk operation
2510 *
2511 * @param solver the solver
2512 */
2513static void
2514GAS_ril_bulk_start (void *solver)
2515{
2516 struct GAS_RIL_Handle *s = solver;
2517
2518 LOG (GNUNET_ERROR_TYPE_DEBUG,
2519 "API_bulk_start() lock: %d\n", s->bulk_lock + 1);
2520
2521 s->bulk_lock++;
2522}
2523
2524
2525/**
2526 * Bulk operation done
2527 *
2528 * @param solver the solver handle
2529 */
2530static void
2531GAS_ril_bulk_stop (void *solver)
2532{
2533 struct GAS_RIL_Handle *s = solver;
2534
2535 LOG (GNUNET_ERROR_TYPE_DEBUG,
2536 "API_bulk_stop() lock: %d\n",
2537 s->bulk_lock - 1);
2538
2539 if (s->bulk_lock < 1)
2540 {
2541 GNUNET_break (0);
2542 return;
2543 }
2544 s->bulk_lock--;
2545
2546 if (0 < s->bulk_changes)
2547 {
2548 ril_step (solver);
2549 s->bulk_changes = 0;
2550 }
2551}
2552
2553
2554/**
2555 * Tell solver to notify ATS if the address to use changes for a specific
2556 * peer using the bandwidth changed callback
2557 *
2558 * The solver must only notify about changes for peers with pending address
2559 * requests!
2560 *
2561 * @param solver the solver handle
2562 * @param peer the identity of the peer
2563 */
2564static void
2565GAS_ril_get_preferred_address (void *solver,
2566 const struct GNUNET_PeerIdentity *peer)
2567{
2568 struct GAS_RIL_Handle *s = solver;
2569 struct RIL_Peer_Agent *agent;
2570
2571 LOG (GNUNET_ERROR_TYPE_DEBUG, "API_get_preferred_address()\n");
2572
2573 agent = ril_get_agent (s, peer, GNUNET_YES);
2574
2575 agent->is_active = GNUNET_YES;
2576 envi_set_active_suggestion (solver, agent, agent->address_inuse, agent->bw_in,
2577 agent->bw_out, GNUNET_YES);
2578
2579 ril_try_unblock_agent (solver, agent, GNUNET_YES);
2580
2581 if (agent->address_inuse)
2582 {
2583 LOG (GNUNET_ERROR_TYPE_DEBUG,
2584 "API_get_preferred_address() Activated agent for peer '%s' with %s address %s\n",
2585 GNUNET_i2s (peer), agent->address_inuse->plugin,
2586 agent->address_inuse->addr);
2587 }
2588 else
2589 {
2590 LOG (GNUNET_ERROR_TYPE_DEBUG,
2591 "API_get_preferred_address() Activated agent for peer '%s', but no address available\n",
2592 GNUNET_i2s (peer));
2593 s->parameters.temperature = s->parameters.temperature_init;
2594 s->parameters.epsilon = s->parameters.epsilon_init;
2595 }
2596 if (NULL != agent->address_inuse)
2597 s->env->bandwidth_changed_cb (s->env->cls,
2598 agent->address_inuse);
2599}
2600
2601
2602/**
2603 * Tell solver stop notifying ATS about changes for this peers
2604 *
2605 * The solver must only notify about changes for peers with pending address
2606 * requests!
2607 *
2608 * @param solver the solver handle
2609 * @param peer the peer
2610 */
2611static void
2612GAS_ril_stop_get_preferred_address (void *solver,
2613 const struct GNUNET_PeerIdentity *peer)
2614{
2615 struct GAS_RIL_Handle *s = solver;
2616 struct RIL_Peer_Agent *agent;
2617
2618 LOG (GNUNET_ERROR_TYPE_DEBUG,
2619 "API_stop_get_preferred_address()");
2620
2621 agent = ril_get_agent (s, peer, GNUNET_NO);
2622
2623 if (NULL == agent)
2624 {
2625 GNUNET_break (0);
2626 return;
2627 }
2628 if (GNUNET_NO == agent->is_active)
2629 {
2630 GNUNET_break (0);
2631 return;
2632 }
2633
2634 s->parameters.temperature = s->parameters.temperature_init;
2635 s->parameters.epsilon = s->parameters.epsilon_init;
2636
2637 agent->is_active = GNUNET_NO;
2638
2639 envi_set_active_suggestion (s, agent, agent->address_inuse, agent->bw_in,
2640 agent->bw_out,
2641 GNUNET_YES);
2642
2643 ril_step (s);
2644
2645 LOG (GNUNET_ERROR_TYPE_DEBUG,
2646 "API_stop_get_preferred_address() Paused agent for peer '%s'\n",
2647 GNUNET_i2s (peer));
2648}
2649
2650
2651/**
2652 * Entry point for the plugin
2653 *
2654 * @param cls pointer to the 'struct GNUNET_ATS_PluginEnvironment'
2655 */
2656void *
2657libgnunet_plugin_ats_ril_init (void *cls)
2658{
2659 static struct GNUNET_ATS_SolverFunctions sf;
2660 struct GNUNET_ATS_PluginEnvironment *env = cls;
2661 struct GAS_RIL_Handle *solver = GNUNET_new (struct GAS_RIL_Handle);
2662 struct RIL_Scope *cur;
2663 int c;
2664 char *string;
2665 float f_tmp;
2666
2667 LOG (GNUNET_ERROR_TYPE_DEBUG,
2668 "API_init() Initializing RIL solver\n");
2669
2670 GNUNET_assert (NULL != env);
2671 GNUNET_assert (NULL != env->cfg);
2672 GNUNET_assert (NULL != env->stats);
2673 GNUNET_assert (NULL != env->bandwidth_changed_cb);
2674 GNUNET_assert (NULL != env->get_preferences);
2675
2676 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "ats",
2677 "RIL_RBF_DIVISOR",
2678 &solver->parameters.
2679 rbf_divisor))
2680 {
2681 solver->parameters.rbf_divisor = RIL_DEFAULT_RBF_DIVISOR;
2682 }
2683
2684 if (GNUNET_OK
2685 != GNUNET_CONFIGURATION_get_value_time (env->cfg, "ats",
2686 "RIL_STEP_TIME_MIN",
2687 &solver->parameters.step_time_min))
2688 {
2689 solver->parameters.step_time_min = RIL_DEFAULT_STEP_TIME_MIN;
2690 }
2691
2692 if (GNUNET_OK
2693 != GNUNET_CONFIGURATION_get_value_time (env->cfg, "ats",
2694 "RIL_STEP_TIME_MAX",
2695 &solver->parameters.step_time_max))
2696 {
2697 solver->parameters.step_time_max = RIL_DEFAULT_STEP_TIME_MAX;
2698 }
2699
2700 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats",
2701 "RIL_ALGORITHM",
2702 &string))
2703 {
2704 GNUNET_STRINGS_utf8_toupper (string, string);
2705 if (0 == strcmp (string, "SARSA"))
2706 {
2707 solver->parameters.algorithm = RIL_ALGO_SARSA;
2708 }
2709 if (0 == strcmp (string, "Q-LEARNING"))
2710 {
2711 solver->parameters.algorithm = RIL_ALGO_Q;
2712 }
2713
2714 GNUNET_free (string);
2715 }
2716 else
2717 {
2718 solver->parameters.algorithm = RIL_DEFAULT_ALGORITHM;
2719 }
2720
2721 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats",
2722 "RIL_SELECT",
2723 &string))
2724 {
2725 solver->parameters.select = ! strcmp (string, "EGREEDY") ?
2726 RIL_SELECT_EGREEDY : RIL_SELECT_SOFTMAX;
2727 GNUNET_free (string);
2728 }
2729 else
2730 {
2731 solver->parameters.select = RIL_DEFAULT_SELECT;
2732 }
2733
2734
2735 solver->parameters.beta = RIL_DEFAULT_DISCOUNT_BETA;
2736 if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
2737 "RIL_DISCOUNT_BETA",
2738 &f_tmp))
2739 {
2740 if (f_tmp < 0.0)
2741 {
2742 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"),
2743 "RIL_DISCOUNT_BETA", f_tmp);
2744 }
2745 else
2746 {
2747 solver->parameters.beta = f_tmp;
2748 LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n",
2749 "RIL_DISCOUNT_BETA", f_tmp);
2750 }
2751 }
2752
2753 solver->parameters.gamma = RIL_DEFAULT_DISCOUNT_GAMMA;
2754 if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
2755 "RIL_DISCOUNT_GAMMA",
2756 &f_tmp))
2757 {
2758 if ((f_tmp < 0.0) || (f_tmp > 1.0))
2759 {
2760 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"),
2761 "RIL_DISCOUNT_GAMMA", f_tmp);
2762 }
2763 else
2764 {
2765 solver->parameters.gamma = f_tmp;
2766 LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n",
2767 "RIL_DISCOUNT_GAMMA", f_tmp);
2768 }
2769 }
2770
2771 solver->parameters.alpha = RIL_DEFAULT_GRADIENT_STEP_SIZE;
2772 if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
2773 "RIL_GRADIENT_STEP_SIZE",
2774 &f_tmp))
2775 {
2776 if ((f_tmp < 0.0) || (f_tmp > 1.0))
2777 {
2778 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"),
2779 "RIL_GRADIENT_STEP_SIZE", f_tmp);
2780 }
2781 else
2782 {
2783 solver->parameters.alpha = f_tmp;
2784 LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n",
2785 "RIL_GRADIENT_STEP_SIZE", f_tmp);
2786 }
2787 }
2788
2789 solver->parameters.lambda = RIL_DEFAULT_TRACE_DECAY;
2790 if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
2791 "RIL_TRACE_DECAY",
2792 &f_tmp))
2793 {
2794 if ((f_tmp < 0.0) || (f_tmp > 1.0))
2795 {
2796 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"),
2797 "RIL_TRACE_DECAY", f_tmp);
2798 }
2799 else
2800 {
2801 solver->parameters.lambda = f_tmp;
2802 LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n",
2803 "RIL_TRACE_DECAY", f_tmp);
2804 }
2805 }
2806
2807 solver->parameters.epsilon_init = RIL_DEFAULT_EXPLORE_RATIO;
2808 if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
2809 "RIL_EXPLORE_RATIO",
2810 &f_tmp))
2811 {
2812 if ((f_tmp < 0.0) || (f_tmp > 1.0))
2813 {
2814 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"),
2815 "RIL_EXPLORE_RATIO", f_tmp);
2816 }
2817 else
2818 {
2819 solver->parameters.epsilon_init = f_tmp;
2820 LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n",
2821 "RIL_EXPLORE_RATIO", f_tmp);
2822 }
2823 }
2824
2825 solver->parameters.epsilon_decay = RIL_DEFAULT_EXPLORE_DECAY;
2826 if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
2827 "RIL_EXPLORE_DECAY",
2828 &f_tmp))
2829 {
2830 if ((f_tmp < 0.0) || (f_tmp > 1.0))
2831 {
2832 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"),
2833 "RIL_EXPLORE_DECAY", f_tmp);
2834 }
2835 else
2836 {
2837 solver->parameters.epsilon_decay = f_tmp;
2838 LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n",
2839 "RIL_EXPLORE_DECAY", f_tmp);
2840 }
2841 }
2842
2843 solver->parameters.temperature_init = RIL_DEFAULT_TEMPERATURE;
2844 if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
2845 "RIL_TEMPERATURE",
2846 &f_tmp))
2847 {
2848 if (f_tmp <= 0.0)
2849 {
2850 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"),
2851 "RIL_TEMPERATURE", f_tmp);
2852 }
2853 else
2854 {
2855 solver->parameters.temperature_init = f_tmp;
2856 LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n",
2857 "RIL_TEMPERATURE", f_tmp);
2858 }
2859 }
2860
2861 solver->parameters.temperature_decay = RIL_DEFAULT_TEMPERATURE_DECAY;
2862 if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats",
2863 "RIL_TEMPERATURE_DECAY",
2864 &f_tmp))
2865 {
2866 if ((f_tmp <= 0.0) ||(solver->parameters.temperature_decay > 1) )
2867 {
2868 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"),
2869 "RIL_TEMPERATURE_DECAY", f_tmp);
2870 }
2871 else
2872 {
2873 solver->parameters.temperature_decay = f_tmp;
2874 LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n",
2875 "RIL_TEMPERATURE_DECAY", f_tmp);
2876 }
2877 }
2878
2879 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "ats",
2880 "RIL_SIMULATE",
2881 &solver->simulate))
2882 {
2883 solver->simulate = GNUNET_NO;
2884 }
2885
2886 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "ats",
2887 "RIL_REPLACE_TRACES"))
2888 {
2889 solver->parameters.eligibility_trace_mode = RIL_E_REPLACE;
2890 }
2891 else
2892 {
2893 solver->parameters.eligibility_trace_mode = RIL_E_ACCUMULATE;
2894 }
2895
2896 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (env->cfg, "ats",
2897 "RIL_SOCIAL_WELFARE",
2898 &string))
2899 {
2900 solver->parameters.social_welfare = ! strcmp (string, "NASH") ?
2901 RIL_WELFARE_NASH :
2902 RIL_WELFARE_EGALITARIAN;
2903 GNUNET_free (string);
2904 }
2905 else
2906 {
2907 solver->parameters.social_welfare = RIL_DEFAULT_WELFARE;
2908 }
2909
2910 solver->env = env;
2911 sf.cls = solver;
2912 sf.s_add = &GAS_ril_address_add;
2913 sf.s_address_update_property = &GAS_ril_address_property_changed;
2914 sf.s_get = &GAS_ril_get_preferred_address;
2915 sf.s_get_stop = &GAS_ril_stop_get_preferred_address;
2916 sf.s_pref = &GAS_ril_address_change_preference;
2917 sf.s_feedback = &GAS_ril_address_preference_feedback;
2918 sf.s_del = &GAS_ril_address_delete;
2919 sf.s_bulk_start = &GAS_ril_bulk_start;
2920 sf.s_bulk_stop = &GAS_ril_bulk_stop;
2921
2922 solver->networks_count = env->network_count;
2923 solver->network_entries = GNUNET_malloc (env->network_count * sizeof(struct
2924 RIL_Scope));
2925 solver->step_count = 0;
2926 solver->done = GNUNET_NO;
2927
2928 for (c = 0; c < env->network_count; c++)
2929 {
2930 cur = &solver->network_entries[c];
2931 cur->type = c;
2932 cur->bw_in_available = env->in_quota[c];
2933 cur->bw_out_available = env->out_quota[c];
2934 LOG (GNUNET_ERROR_TYPE_DEBUG,
2935 "init() Quotas for %s network: IN %llu - OUT %llu\n",
2936 GNUNET_NT_to_string (cur->type),
2937 cur->bw_in_available / 1024,
2938 cur->bw_out_available / 1024);
2939 }
2940
2941 LOG (GNUNET_ERROR_TYPE_DEBUG, "init() Parameters:\n");
2942 LOG (GNUNET_ERROR_TYPE_DEBUG,
2943 "init() Algorithm = %s, alpha = %f, beta = %f, lambda = %f\n",
2944 solver->parameters.algorithm ? "Q" : "SARSA",
2945 solver->parameters.alpha,
2946 solver->parameters.beta,
2947 solver->parameters.lambda);
2948 LOG (GNUNET_ERROR_TYPE_DEBUG,
2949 "init() exploration_ratio = %f, temperature = %f, ActionSelection = %s\n",
2950 solver->parameters.epsilon,
2951 solver->parameters.temperature,
2952 solver->parameters.select ? "EGREEDY" : "SOFTMAX");
2953 LOG (GNUNET_ERROR_TYPE_DEBUG, "init() RBF_DIVISOR = %llu\n",
2954 solver->parameters.rbf_divisor);
2955
2956 return &sf;
2957}
2958
2959
2960/**
2961 * Exit point for the plugin
2962 *
2963 * @param cls the solver handle
2964 */
2965void *
2966libgnunet_plugin_ats_ril_done (void *cls)
2967{
2968 struct GNUNET_ATS_SolverFunctions *sf = cls;
2969 struct GAS_RIL_Handle *s = sf->cls;
2970 struct RIL_Peer_Agent *cur_agent;
2971 struct RIL_Peer_Agent *next_agent;
2972
2973 LOG (GNUNET_ERROR_TYPE_DEBUG, "API_done() Shutting down RIL solver\n");
2974
2975 s->done = GNUNET_YES;
2976
2977 cur_agent = s->agents_head;
2978 while (NULL != cur_agent)
2979 {
2980 next_agent = cur_agent->next;
2981 GNUNET_CONTAINER_DLL_remove (s->agents_head, s->agents_tail, cur_agent);
2982 agent_die (s, cur_agent);
2983 cur_agent = next_agent;
2984 }
2985
2986 if (NULL != s->step_next_task_id)
2987 {
2988 GNUNET_SCHEDULER_cancel (s->step_next_task_id);
2989 }
2990 GNUNET_free (s->network_entries);
2991 GNUNET_free (s);
2992
2993 return NULL;
2994}
2995
2996
2997/* end of plugin_ats_ril.c */
diff --git a/src/ats/test_ats2_lib.c b/src/ats/test_ats2_lib.c
deleted file mode 100644
index f2a8eb1ea..000000000
--- a/src/ats/test_ats2_lib.c
+++ /dev/null
@@ -1,259 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18/**
19 * @file ats/test_ats2_lib.c
20 * @brief test ATS library with a generic interpreter for running ATS tests
21 * @author Julius Bünger
22 */
23#include "platform.h"
24#include "gnunet_util_lib.h"
25#include "gnunet_ats_application_service.h"
26#include "gnunet_ats_transport_service.h"
27#include "gnunet_testing_lib.h"
28
29/**
30 * @brief Indicates the success of the whole test
31 */
32static int ret;
33
34/**
35 * @brief The time available until the test shuts down
36 */
37static struct GNUNET_TIME_Relative timeout;
38
39/**
40 * @brief ATS Application Handle
41 *
42 * Handle to the application-side of ATS.
43 */
44static struct GNUNET_ATS_ApplicationHandle *ah;
45
46/**
47 * @brief ATS Transport Handle
48 *
49 * Handle to the transport-side of ATS.
50 */
51static struct GNUNET_ATS_TransportHandle *th;
52
53/**
54 * @brief Another (dummy) peer.
55 *
56 * Used as the peer ATS shall allocate bandwidth to.
57 */
58static struct GNUNET_PeerIdentity other_peer;
59
60/**
61 * @brief Handle to the session record
62 */
63static struct GNUNET_ATS_SessionRecord *sr;
64
65
66/**
67 * @brief Called whenever allocation changed
68 *
69 * Implements #GNUNET_ATS_AllocationCallback
70 *
71 * @param cls
72 * @param session
73 * @param bandwidth_out
74 * @param bandwidth_in
75 *
76 * @return
77 */
78static void
79allocation_cb (void *cls,
80 struct GNUNET_ATS_Session *session,
81 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
82 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
83{
84 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
85 "allocation_cb() called\n");
86}
87
88
89/**
90 * @brief Called whenever suggestion is made
91 *
92 * Implements #GNUNET_ATS_SuggestionCallback
93 *
94 * @param cls
95 * @param pid
96 * @param address
97 */
98static void
99suggestion_cb (void *cls,
100 const struct GNUNET_PeerIdentity *pid,
101 const char *address)
102{
103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
104 "suggestion_cb() called\n");
105 ret = 0;
106}
107
108
109/**
110 * @brief Initialise both 'sides' of ATS
111 *
112 * Initialises the application and transportation side of ATS.
113 */
114static void
115init_both (const struct GNUNET_CONFIGURATION_Handle *cfg)
116{
117 ah = GNUNET_ATS_application_init (cfg);
118 GNUNET_assert (NULL != ah);
119 th = GNUNET_ATS_transport_init (cfg,
120 &allocation_cb,
121 NULL,
122 &suggestion_cb,
123 NULL);
124 GNUNET_assert (NULL != ah);
125}
126
127
128/**
129 * @brief Disconnect both 'sides' of ATS
130 */
131static void
132finish_both (void)
133{
134 GNUNET_ATS_application_done (ah);
135 ah = NULL;
136 GNUNET_ATS_transport_done (th);
137 th = NULL;
138}
139
140
141/**
142 * @brief Provide information about the start of an imaginary connection
143 */
144static void
145provide_info_start (void)
146{
147 struct GNUNET_ATS_Properties prop = {
148 .delay = GNUNET_TIME_UNIT_FOREVER_REL,
149 .goodput_out = 1048576,
150 .goodput_in = 1048576,
151 .utilization_out = 0,
152 .utilization_in = 0,
153 .distance = 0,
154 .mtu = UINT32_MAX,
155 .nt = GNUNET_NT_UNSPECIFIED,
156 .cc = GNUNET_TRANSPORT_CC_UNKNOWN,
157 };
158
159 sr = GNUNET_ATS_session_add (th,
160 &other_peer,
161 "test-address",
162 NULL,
163 &prop);
164 GNUNET_assert (NULL != sr);
165}
166
167
168/**
169 * @brief Provide information about the end of an imaginary connection
170 */
171static void
172provide_info_end (void)
173{
174 GNUNET_ATS_session_del (sr);
175}
176
177
178/**
179 * @brief Inform ATS about the need of a connection towards a peer
180 */
181static void
182get_suggestion (void)
183{
184 struct GNUNET_ATS_ApplicationSuggestHandle *ash;
185
186 ash = GNUNET_ATS_application_suggest (ah,
187 &other_peer,
188 GNUNET_MQ_PREFERENCE_NONE,
189 GNUNET_BANDWIDTH_VALUE_MAX);
190 GNUNET_assert (NULL != ash);
191}
192
193
194static void
195on_shutdown (void *cls)
196{
197 provide_info_end ();
198 finish_both ();
199 GNUNET_SCHEDULER_shutdown ();
200}
201
202
203/**
204 * Function run once the ATS service has been started.
205 *
206 * @param cls NULL
207 * @param cfg configuration for the testcase
208 * @param peer handle to the peer
209 */
210static void
211run (void *cls,
212 const struct GNUNET_CONFIGURATION_Handle *cfg,
213 struct GNUNET_TESTING_Peer *peer)
214{
215 init_both (cfg);
216 provide_info_start ();
217 get_suggestion ();
218 (void) GNUNET_SCHEDULER_add_delayed (timeout,
219 &on_shutdown,
220 NULL);
221}
222
223
224/**
225 * @brief Starts the gnunet-testing peer
226 *
227 * @param argc
228 * @param argv[]
229 *
230 * @return
231 */
232int
233main (int argc,
234 char *argv[])
235{
236 ret = 1;
237 memset (&other_peer, 0, sizeof(struct GNUNET_PeerIdentity));
238 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
239 2);
240 if (0 != GNUNET_TESTING_peer_run ("test-ats2-lib",
241 "test_ats2_lib.conf",
242 &run, NULL))
243 {
244 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
245 "Running the testing peer failed.\n");
246 return 1;
247 }
248 if (0 != ret)
249 {
250 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
251 "Global status indicates unsuccessful testrun - probably allocation_cb was not called.\n");
252 ret = 77; // SKIP test, test not yet right!
253 }
254 return ret;
255}
256
257
258
259/* end of test_ats2_lib.c */
diff --git a/src/ats/test_ats2_lib.conf b/src/ats/test_ats2_lib.conf
deleted file mode 100644
index e24f5ea68..000000000
--- a/src/ats/test_ats2_lib.conf
+++ /dev/null
@@ -1,13 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2@INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf
3
4[ats]
5BINARY = gnunet-service-ats-new
6
7[core]
8START_ON_DEMAND = NO
9IMMEDIATE_START = NO
10
11[transport]
12START_ON_DEMAND = NO
13IMMEDIATE_START = NO
diff --git a/src/ats/test_ats2_lib.h b/src/ats/test_ats2_lib.h
deleted file mode 100644
index 090abc20d..000000000
--- a/src/ats/test_ats2_lib.h
+++ /dev/null
@@ -1,523 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18/**
19 * @file ats/test_ats_lib.h
20 * @brief test ATS library with a generic interpreter for running ATS tests
21 * @author Christian Grothoff
22 */
23#ifndef TEST_ATS_LIB_H
24#define TEST_ATS_LIB_H
25
26#include "gnunet_util_lib.h"
27#include "gnunet_ats_application_service.h"
28#include "gnunet_ats_transport_service.h"
29#include "gnunet_testing_lib.h"
30
31
32///**
33// * Commands for the interpreter.
34// */
35// enum CommandCode
36// {
37// /**
38// * End the test (passing).
39// */
40// CMD_END_PASS = 0,
41//
42// /**
43// * Call #GNUNET_ATS_address_add().
44// */
45// CMD_ADD_ADDRESS,
46//
47// /**
48// * Call #GNUNET_ATS_address_del().
49// */
50// CMD_DEL_ADDRESS,
51//
52// /**
53// * Wait for ATS to suggest address.
54// */
55// CMD_AWAIT_ADDRESS_SUGGESTION,
56//
57// /**
58// * Wait for ATS to suggest disconnect.
59// */
60// CMD_AWAIT_DISCONNECT_SUGGESTION,
61//
62// /**
63// * Ask ATS to connect to a peer, using
64// * #GNUNET_ATS_connectivity_suggest().
65// */
66// CMD_REQUEST_CONNECTION_START,
67//
68// /**
69// * Tell ATS we no longer need a connection to a peer, using
70// * #GNUNET_ATS_connectivity_suggest_cancel().
71// */
72// CMD_REQUEST_CONNECTION_STOP,
73//
74// /**
75// * Wait for certain address information to be provided.
76// */
77// CMD_AWAIT_ADDRESS_INFORMATION,
78//
79// /**
80// * Update properties of an address, using
81// * #GNUNET_ATS_address_update().
82// */
83// CMD_UPDATE_ADDRESS,
84//
85// /**
86// * Add session to an address, using
87// * #GNUNET_ATS_address_add_session().
88// */
89// CMD_ADD_SESSION,
90//
91// /**
92// * Remove session from an address, using
93// * #GNUNET_ATS_address_del_session().
94// */
95// CMD_DEL_SESSION,
96//
97// /**
98// * Change performance preferences for a peer, testing
99// * #GNUNET_ATS_performance_change_preference().
100// */
101// CMD_CHANGE_PREFERENCE,
102//
103// /**
104// * Provide allocation quality feedback, testing
105// * #GNUNET_ATS_performance_give_feedback().
106// */
107// CMD_PROVIDE_FEEDBACK,
108//
109// /**
110// * Obtain list of all addresses, testing
111// * #GNUNET_ATS_performance_list_addresses().
112// */
113// CMD_LIST_ADDRESSES,
114//
115// /**
116// * Reserve bandwidth, testing
117// * #GNUNET_ATS_reserve_bandwidth().
118// */
119// CMD_RESERVE_BANDWIDTH,
120//
121// /**
122// * Wait for a bit.
123// */
124// CMD_SLEEP
125//
126// };
127//
128//
129///**
130// * Details for the #CMD_ADD_ADDRESS command.
131// */
132// struct CommandAddAddress
133// {
134// /**
135// * Number of the peer (used to generate PID).
136// */
137// unsigned int pid;
138//
139// /**
140// * Number of the address (used to generate binary address).
141// */
142// unsigned int addr_num;
143//
144// /**
145// * Session to supply, 0 for NULL.
146// */
147// unsigned int session;
148//
149// /**
150// * Flags to set for the address.
151// */
152// enum GNUNET_HELLO_AddressInfo addr_flags;
153//
154// /**
155// * Performance properties to supply.
156// */
157// struct GNUNET_ATS_Properties properties;
158//
159// /**
160// * Expect the operation to fail (duplicate).
161// */
162// int expect_fail;
163//
164// /**
165// * Here the result of the add address operation will be stored.
166// */
167// struct GNUNET_ATS_AddressRecord *ar;
168// };
169//
170//
171///**
172// * Details for the #CMD_DEL_ADDRESS command.
173// */
174// struct CommandDelAddress
175// {
176// /**
177// * Label of the corresponding #CMD_ADD_ADDRESS that
178// * we are now to remove.
179// */
180// const char *add_label;
181// };
182//
183//
184///**
185// * Details for the #CMD_AWAIT_ADDRESS_SUGGESTION command.
186// */
187// struct CommandAwaitAddressSuggestion
188// {
189// /**
190// * For which peer do we expect a suggestion?
191// */
192// unsigned int pid;
193//
194// /**
195// * If we expect the address suggested to match a particular
196// * addition, specify the label of the add operation here. Otherwise
197// * use NULL for "any" available address.
198// */
199// const char *add_label;
200//
201// };
202//
203//
204///**
205// * Details for the #CMD_AWAIT_DISCONNECT_SUGGESTION command.
206// */
207// struct CommandAwaitDisconnectSuggestion
208// {
209// /**
210// * For which peer do we expect the disconnect?
211// */
212// unsigned int pid;
213//
214// };
215//
216//
217///**
218// * Details for the #CMD_REQUEST_CONNECTION_START command.
219// */
220// struct CommandRequestConnectionStart
221// {
222// /**
223// * Identity of the peer we would like to connect to.
224// */
225// unsigned int pid;
226//
227// /**
228// * Location where we store the handle returned from
229// * #GNUNET_ATS_connectivity_suggest().
230// */
231// struct GNUNET_ATS_ConnectivitySuggestHandle *csh;
232// };
233//
234//
235///**
236// * Details for the #CMD_REQUEST_CONNECTION_STOP command.
237// */
238// struct CommandRequestConnectionStop
239// {
240// /**
241// * Label of the corresponding #CMD_REQUEST_CONNECTION_START that
242// * we are now stopping.
243// */
244// const char *connect_label;
245// };
246//
247//
248///**
249// * Details for the #CMD_AWAIT_ADDRESS_INFORMATION command.
250// */
251// struct CommandAwaitAddressInformation
252// {
253// /**
254// * For which address do we expect information?
255// * The address is identified by the respective
256// * label of the corresponding add operation.
257// */
258// const char *add_label;
259//
260// /**
261// * Label of a possible update operation that may
262// * have modified the properties. NULL to use
263// * the properties from the @e add_label.
264// */
265// const char *update_label;
266//
267// };
268//
269//
270///**
271// * Details for the #CMD_UPDATE_ADDRESS command.
272// */
273// struct CommandUpdateAddress
274// {
275// /**
276// * Label of the addresses's add operation.
277// */
278// const char *add_label;
279//
280// /**
281// * Performance properties to supply.
282// */
283// struct GNUNET_ATS_Properties properties;
284//
285// };
286//
287//
288///**
289// * Details for the #CMD_ADD_SESSION command.
290// */
291// struct CommandAddSession
292// {
293// /**
294// * Label of the addresses's add operation.
295// */
296// const char *add_label;
297//
298// /**
299// * Session to supply.
300// */
301// unsigned int session;
302//
303// };
304//
305//
306///**
307// * Details for the #CMD_DEL_SESSION command.
308// */
309// struct CommandDelSession
310// {
311// /**
312// * Label of the addresses's add operation.
313// */
314// const char *add_session_label;
315//
316// };
317//
318//
319///**
320// * Details for the #CMD_CHANGE_PREFERENCE command.
321// */
322// struct CommandChangePreference
323// {
324// /**
325// * Identity of the peer we have a preference change towards.
326// */
327// unsigned int pid;
328//
329// /* FIXME: preference details! */
330//
331// };
332//
333//
334///**
335// * Details for the #CMD_PROVIDE_FEEDBACK command.
336// */
337// struct CommandProvideFeedback
338// {
339// /**
340// * Identity of the peer we have a feedback for.
341// */
342// unsigned int pid;
343//
344// /**
345// * Over which timeframe does the feedback apply?
346// */
347// struct GNUNET_TIME_Relative scope;
348//
349// /* FIXME: feedback details! */
350// };
351//
352//
353///**
354// * Details for the #CMD_LIST_ADDRESSES command.
355// */
356// struct CommandListAddresses
357// {
358// /**
359// * Identity of the peer we want a list for.
360// */
361// unsigned int pid;
362//
363// /**
364// * All addresses or just active?
365// */
366// int all;
367//
368// /**
369// * Minimum number of addresses the callback may report.
370// */
371// unsigned int min_calls;
372//
373// /**
374// * Maximum number of addresses the callback may report.
375// */
376// unsigned int max_calls;
377//
378// /**
379// * Minimum number of active addresses the callback may report.
380// */
381// unsigned int min_active_calls;
382//
383// /**
384// * Maximum number of active addresses the callback may report.
385// */
386// unsigned int max_active_calls;
387//
388// /**
389// * Number of calls the command invoked the callback with
390// * an address marked as active. (Set by command).
391// */
392// unsigned int active_calls;
393//
394// /**
395// * Number of calls the command invoked the callback with
396// * any address marked as available to ATS. (Set by command).
397// */
398// unsigned int calls;
399//
400// /**
401// * Location where we store the return value from
402// * #GNUNET_ATS_performance_list_addresses().
403// */
404// struct GNUNET_ATS_AddressListHandle *alh;
405//
406// };
407//
408//
409///**
410// * Details for the #CMD_RESERVE_BANDWIDTH command.
411// */
412// struct CommandReserveBandwidth
413// {
414// /**
415// * For which peer do we reserve bandwidth?
416// */
417// unsigned int pid;
418//
419// /**
420// * How much should we try to reserve?
421// */
422// int32_t amount;
423//
424// /**
425// * Should we expect this to work or fail?
426// * #GNUNET_YES: must work
427// * #GNUNET_NO: may work or fail
428// * #GNUNET_SYSERR: must fail
429// */
430// int expected_result;
431//
432// /**
433// * Location where we store the return value from
434// * #GNUNET_ATS_reserve_bandwidth().
435// */
436// struct GNUNET_ATS_ReservationContext *rc;
437//
438// };
439//
440//
441///**
442// * Details for the #CMD_SLEEP command.
443// */
444// struct CommandSleep
445// {
446// /**
447// * How long should we wait before running the next command?
448// */
449// struct GNUNET_TIME_Relative delay;
450// };
451//
452//
453///**
454// * A command for the test case interpreter.
455// */
456// struct Command
457// {
458// /**
459// * Command code to run.
460// */
461// enum CommandCode code;
462//
463// /**
464// * Commands can be given a label so we can reference them later.
465// */
466// const char *label;
467//
468// /**
469// * Additional arguments to commands, if any.
470// */
471// union {
472//
473// struct CommandAddAddress add_address;
474//
475// struct CommandDelAddress del_address;
476//
477// struct CommandAwaitAddressSuggestion await_address_suggestion;
478//
479// struct CommandAwaitDisconnectSuggestion await_disconnect_suggestion;
480//
481// struct CommandRequestConnectionStart request_connection_start;
482//
483// struct CommandRequestConnectionStop request_connection_stop;
484//
485// struct CommandAwaitAddressInformation await_address_information;
486//
487// struct CommandUpdateAddress update_address;
488//
489// struct CommandAddSession add_session;
490//
491// struct CommandDelSession del_session;
492//
493// struct CommandChangePreference change_preference;
494//
495// struct CommandProvideFeedback provide_feedback;
496//
497// struct CommandListAddresses list_addresses;
498//
499// struct CommandReserveBandwidth reserve_bandwidth;
500//
501// struct CommandSleep sleep;
502//
503// } details;
504//
505// };
506
507
508/**
509 * Run ATS test.
510 *
511 * @param argc length of @a argv
512 * @param argv command line
513 * @param cmds commands to run with the interpreter
514 * @param timeout how long is the test allowed to take?
515 * @return 0 on success
516 */
517int
518TEST_ATS_run (int argc,
519 char *argv[],
520 struct Command *cmds,
521 struct GNUNET_TIME_Relative timeout);
522
523#endif
diff --git a/src/ats/test_ats_api_mlp.conf b/src/ats/test_ats_api_mlp.conf
deleted file mode 100644
index d5f05a3c4..000000000
--- a/src/ats/test_ats_api_mlp.conf
+++ /dev/null
@@ -1,45 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-ats-mlp/
5
6[ats]
7# Enable MLP mode (default: NO)
8MODE = mlp
9# Network specific inbound/outbound quotas
10# UNSPECIFIED
11UNSPECIFIED_QUOTA_IN = unlimited
12UNSPECIFIED_QUOTA_OUT = unlimited
13# LOOPBACK
14LOOPBACK_QUOTA_IN = unlimited
15LOOPBACK_QUOTA_OUT = unlimited
16# LAN
17LAN_QUOTA_IN = unlimited
18LAN_QUOTA_OUT = unlimited
19# WAN
20WAN_QUOTA_IN = 64 KiB
21WAN_QUOTA_OUT = 64 KiB
22# WLAN
23WLAN_QUOTA_IN = 4096
24WLAN_QUOTA_OUT = 4096
25
26# MLP specific settings
27ATS_MIN_INTERVAL = 15000
28ATS_EXEC_INTERVAL = 30000
29
30# MLP defaults
31# MLP_MAX_DURATION = 3 s
32# MLP_MAX_ITERATIONS = 1024
33# MLP_COEFFICIENT_D = 1.0
34# MLP_COEFFICIENT_U = 1.0
35# MLP_COEFFICIENT_R = 1.0
36# MLP_MIN_BANDWIDTH = 1024
37# MLP_MIN_CONNECTIONS = 4
38
39# MLP Debugging settings
40DUMP_MLP = NO
41DUMP_SOLUTION = NO
42DUMP_OVERWRITE = NO
43DUMP_MIN_PEERS = 0
44DUMP_MIN_ADDRS = 0
45DUMP_OVERWRITE = NO
diff --git a/src/ats/test_ats_api_ril.conf b/src/ats/test_ats_api_ril.conf
deleted file mode 100644
index 5f5fb006b..000000000
--- a/src/ats/test_ats_api_ril.conf
+++ /dev/null
@@ -1,24 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-ats-ril/
5
6[ats]
7# Enable RIL mode (default: NO)
8MODE = ril
9# Network specific inbound/outbound quotas
10# UNSPECIFIED
11UNSPECIFIED_QUOTA_IN = unlimited
12UNSPECIFIED_QUOTA_OUT = unlimited
13# LOOPBACK
14LOOPBACK_QUOTA_IN = unlimited
15LOOPBACK_QUOTA_OUT = unlimited
16# LAN
17LAN_QUOTA_IN = unlimited
18LAN_QUOTA_OUT = unlimited
19# WAN
20WAN_QUOTA_IN = 64 KiB
21WAN_QUOTA_OUT = 64 KiB
22# WLAN
23WLAN_QUOTA_IN = 4096
24WLAN_QUOTA_OUT = 4096
diff --git a/src/ats/test_ats_solver_delayed_mlp.conf b/src/ats/test_ats_solver_delayed_mlp.conf
deleted file mode 100644
index 632755570..000000000
--- a/src/ats/test_ats_solver_delayed_mlp.conf
+++ /dev/null
@@ -1,20 +0,0 @@
1@INLINE@ test_ats_solver_default.conf
2
3[ats]
4PREFIX = ./test_delay -t 10 --
5MODE = mlp
6# UNSPECIFIED
7UNSPECIFIED_QUOTA_IN = 64 KiB
8UNSPECIFIED_QUOTA_OUT = 64 KiB
9# LOOPBACK
10LOOPBACK_QUOTA_IN = unlimited
11LOOPBACK_QUOTA_OUT = unlimited
12# LAN
13LAN_QUOTA_IN = unlimited
14LAN_QUOTA_OUT = unlimited
15# WAN
16WAN_QUOTA_IN = 64 KiB
17WAN_QUOTA_OUT = 64 KiB
18# WLAN
19WLAN_QUOTA_IN = 512
20WLAN_QUOTA_OUT = 512
diff --git a/src/ats/test_ats_solver_delayed_ril.conf b/src/ats/test_ats_solver_delayed_ril.conf
deleted file mode 100644
index a43fffa4c..000000000
--- a/src/ats/test_ats_solver_delayed_ril.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ test_ats_solver_default.conf
2
3[ats]
4PREFIX = ./test_delay -t 10 --
5MODE = ril
6# UNSPECIFIED
7UNSPECIFIED_QUOTA_IN = 64 KiB
8UNSPECIFIED_QUOTA_OUT = 64 KiB
9# LOOPBACK
10LOOPBACK_QUOTA_IN = unlimited
11LOOPBACK_QUOTA_OUT = unlimited
12# LAN
13LAN_QUOTA_IN = unlimited
14LAN_QUOTA_OUT = unlimited
15# WAN
16WAN_QUOTA_IN = 64 KiB
17WAN_QUOTA_OUT = 64 KiB
18# WLAN
19WLAN_QUOTA_IN = 512
20WLAN_QUOTA_OUT = 512
21
22# Reinforcement Learning Parameters
23RIL_STEP_TIME_MIN = 500 ms
24RIL_STEP_TIME_MAX = 1000 ms
25
26RIL_ALGORITHM = Q
27RIL_DISCOUNT_BETA = 0.7
28RIL_GRADIENT_STEP_SIZE = 0.3
29RIL_TRACE_DECAY = 0.2
30RIL_EXPLORE_RATIO = 0.1
31RIL_GLOBAL_REWARD_SHARE = 1
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index d5c097341..9e0813425 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -29,7 +29,6 @@ gnunetinclude_HEADERS = \
29 gnunet_ats_application_service.h \ 29 gnunet_ats_application_service.h \
30 gnunet_ats_transport_service.h \ 30 gnunet_ats_transport_service.h \
31 gnunet_ats_plugin.h \ 31 gnunet_ats_plugin.h \
32 gnunet_ats_plugin_new.h \
33 gnunet_bandwidth_lib.h \ 32 gnunet_bandwidth_lib.h \
34 gnunet_bio_lib.h \ 33 gnunet_bio_lib.h \
35 gnunet_block_lib.h \ 34 gnunet_block_lib.h \
diff --git a/src/include/gnunet_ats_plugin_new.h b/src/include/gnunet_ats_plugin_new.h
deleted file mode 100644
index b371321fa..000000000
--- a/src/include/gnunet_ats_plugin_new.h
+++ /dev/null
@@ -1,247 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2009-2015, 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Christian Grothoff
23 *
24 * @file
25 * API for the ATS solvers.
26 *
27 * @defgroup ats-plugin ATS service plugin API
28 * Plugin API for the ATS service.
29 *
30 * Specifies the struct that is given to the plugin's entry method and the other
31 * struct that must be returned. Note that the destructors of ATS plugins will
32 * be given the value returned by the constructor and is expected to return a
33 * NULL pointer.
34 *
35 * @{
36 */
37#ifndef PLUGIN_ATS_H
38#define PLUGIN_ATS_H
39
40#include "gnunet_util_lib.h"
41#include "gnunet_ats_application_service.h"
42#include "gnunet_ats_transport_service.h"
43#include "gnunet_statistics_service.h"
44
45
46/**
47 * Preference being expressed by an application client.
48 */
49struct GNUNET_ATS_Preference
50{
51 /**
52 * Peer to get address suggestions for.
53 */
54 struct GNUNET_PeerIdentity peer;
55
56 /**
57 * How much bandwidth in bytes/second does the application expect?
58 */
59 struct GNUNET_BANDWIDTH_Value32NBO bw;
60
61 /**
62 * What type of performance preference does the client have?
63 */
64 enum GNUNET_MQ_PreferenceKind pk;
65};
66
67
68/**
69 * Opaque representation of a session the plugin can allocate bandwidth for.
70 */
71struct GNUNET_ATS_Session;
72
73/**
74 * Plugin-relevant information about a session.
75 */
76struct GNUNET_ATS_SessionData
77{
78 /**
79 * Peer the session is with.
80 */
81 struct GNUNET_PeerIdentity peer;
82
83 /**
84 * ATS performance characteristics for a session.
85 */
86 struct GNUNET_ATS_Properties prop;
87
88 /**
89 * Handle to the session that has the given properties.
90 */
91 struct GNUNET_ATS_Session *session;
92
93 /**
94 * Is the session inbound only?
95 */
96 int inbound_only;
97};
98
99/**
100 * Internal representation of a preference by the plugin.
101 * (If desired, plugin may just use NULL.)
102 */
103struct GNUNET_ATS_PreferenceHandle;
104
105/**
106 * Internal representation of a session by the plugin.
107 * (If desired, plugin may just use NULL.)
108 */
109struct GNUNET_ATS_SessionHandle;
110
111
112/**
113 * Solver functions.
114 *
115 * Each solver is required to set up and return an instance
116 * of this struct during initialization.
117 */
118struct GNUNET_ATS_SolverFunctions
119{
120 /**
121 * Closure to pass to all solver functions in this struct.
122 */
123 void *cls;
124
125 /**
126 * The plugin should begin to respect a new preference.
127 *
128 * @param cls the closure
129 * @param pref the preference to add
130 * @return plugin's internal representation, or NULL
131 */
132 struct GNUNET_ATS_PreferenceHandle *
133 (*preference_add)(void *cls,
134 const struct GNUNET_ATS_Preference *pref);
135
136 /**
137 * The plugin should end respecting a preference.
138 *
139 * @param cls the closure
140 * @param ph whatever @e preference_add returned
141 * @param pref the preference to delete
142 * @return plugin's internal representation, or NULL
143 */
144 void
145 (*preference_del)(void *cls,
146 struct GNUNET_ATS_PreferenceHandle *ph,
147 const struct GNUNET_ATS_Preference *pref);
148
149 /**
150 * Transport established a new session with performance
151 * characteristics given in @a data.
152 *
153 * @param cls closure
154 * @param data performance characteristics of @a sh
155 * @param address address information (for debugging)
156 * @return handle by which the plugin will identify this session
157 */
158 struct GNUNET_ATS_SessionHandle *
159 (*session_add)(void *cls,
160 const struct GNUNET_ATS_SessionData *data,
161 const char *address);
162
163 /**
164 * @a data changed for a given @a sh, solver should consider
165 * the updated performance characteristics.
166 *
167 * @param cls closure
168 * @param sh session this is about
169 * @param data performance characteristics of @a sh
170 */
171 void
172 (*session_update)(void *cls,
173 struct GNUNET_ATS_SessionHandle *sh,
174 const struct GNUNET_ATS_SessionData *data);
175
176 /**
177 * A session went away. Solver should update accordingly.
178 *
179 * @param cls closure
180 * @param sh session this is about
181 * @param data (last) performance characteristics of @a sh
182 */
183 void
184 (*session_del)(void *cls,
185 struct GNUNET_ATS_SessionHandle *sh,
186 const struct GNUNET_ATS_SessionData *data);
187};
188
189
190/**
191 * The ATS plugin will pass a pointer to a struct
192 * of this type as to the initialization function
193 * of the ATS plugins.
194 */
195struct GNUNET_ATS_PluginEnvironment
196{
197 /**
198 * Configuration handle to be used by the solver
199 */
200 const struct GNUNET_CONFIGURATION_Handle *cfg;
201
202 /**
203 * Statistics handle to be used by the solver
204 */
205 struct GNUNET_STATISTICS_Handle *stats;
206
207 /**
208 * Closure to pass to all callbacks in this struct.
209 */
210 void *cls;
211
212 /**
213 * Suggest to the transport that it should try establishing
214 * a connection using the given address.
215 *
216 * @param cls closure, NULL
217 * @param pid peer this is about
218 * @param address address the transport should try
219 */
220 void
221 (*suggest_cb) (void *cls,
222 const struct GNUNET_PeerIdentity *pid,
223 const char *address);
224
225 /**
226 * Tell the transport that it should allocate the given
227 * bandwidth to the specified session.
228 *
229 * @param cls closure, NULL
230 * @param session session this is about
231 * @param peer peer this is about
232 * @param bw_in suggested bandwidth for receiving
233 * @param bw_out suggested bandwidth for transmission
234 */
235 void
236 (*allocate_cb) (void *cls,
237 struct GNUNET_ATS_Session *session,
238 const struct GNUNET_PeerIdentity *peer,
239 struct GNUNET_BANDWIDTH_Value32NBO bw_in,
240 struct GNUNET_BANDWIDTH_Value32NBO bw_out);
241};
242
243
244
245#endif
246
247/** @} */ /* end of group */