tolerate additional IPv4 address now available for gnunet.org
[oweals/gnunet.git] / src / ats-tests / ats-testing-traffic.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010-2013, 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-tests/ats-testing-traffic.c
22  * @brief ats benchmark: traffic generator
23  * @author Christian Grothoff
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "ats-testing.h"
29
30 static struct TrafficGenerator *tg_head;
31 static struct TrafficGenerator *tg_tail;
32
33 extern struct GNUNET_ATS_TEST_Topology *top;
34
35 static struct GNUNET_TIME_Relative
36 get_delay (struct TrafficGenerator *tg)
37 {
38   struct GNUNET_TIME_Relative delay;
39   struct GNUNET_TIME_Relative time_delta;
40   long long int cur_rate;
41   long long int delta_rate;
42
43   delay.rel_value_us = 0;
44
45   /* Calculate the current transmission rate based on the type of traffic */
46   switch (tg->type) {
47     case GNUNET_ATS_TEST_TG_CONSTANT:
48       if (UINT32_MAX == tg->base_rate)
49         return GNUNET_TIME_UNIT_ZERO;
50       cur_rate = tg->base_rate;
51       break;
52     case GNUNET_ATS_TEST_TG_LINEAR:
53       time_delta = GNUNET_TIME_absolute_get_duration(tg->time_start);
54       /* Calculate point of time in the current period */
55       time_delta.rel_value_us = time_delta.rel_value_us % tg->duration_period.rel_value_us;
56       delta_rate = ((double) time_delta.rel_value_us  / tg->duration_period.rel_value_us) *
57           (tg->max_rate - tg->base_rate);
58       if ((tg->max_rate < tg->base_rate) && ((tg->max_rate - tg->base_rate) > tg->base_rate))
59       {
60         /* This will cause an underflow */
61         GNUNET_break (0);
62       }
63       cur_rate = tg->base_rate + delta_rate;
64       break;
65     case GNUNET_ATS_TEST_TG_RANDOM:
66       cur_rate = tg->base_rate + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
67           tg->max_rate - tg->base_rate);
68       break;
69     case GNUNET_ATS_TEST_TG_SINUS:
70       time_delta = GNUNET_TIME_absolute_get_duration(tg->time_start);
71       /* Calculate point of time in the current period */
72       time_delta.rel_value_us = time_delta.rel_value_us % tg->duration_period.rel_value_us;
73       if ((tg->max_rate - tg->base_rate) > tg->base_rate)
74       {
75         /* This will cause an underflow for second half of sinus period,
76          * will be detected in general when experiments are loaded */
77         GNUNET_break (0);
78       }
79       delta_rate = (tg->max_rate - tg->base_rate) *
80           sin ( (2 * M_PI) / ((double) tg->duration_period.rel_value_us) * time_delta.rel_value_us);
81       cur_rate = tg->base_rate + delta_rate;
82       break;
83     default:
84       return delay;
85       break;
86   }
87
88   if (cur_rate < 0)
89   {
90     cur_rate = 1;
91   }
92   /* Calculate the delay for the next message based on the current delay  */
93   delay.rel_value_us =  GNUNET_TIME_UNIT_SECONDS.rel_value_us * TEST_MESSAGE_SIZE / cur_rate;
94
95   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
96               "Current rate is %lld, calculated delay is %llu\n",
97               cur_rate,
98               (unsigned long long) delay.rel_value_us);
99   return delay;
100 }
101
102
103 static void
104 update_ping_data (void *cls)
105 {
106   struct BenchmarkPartner *p = cls;
107   struct GNUNET_TIME_Relative delay;
108
109   p->messages_sent++;
110   p->bytes_sent += TEST_MESSAGE_SIZE;
111   p->me->total_messages_sent++;
112   p->me->total_bytes_sent += TEST_MESSAGE_SIZE;
113
114   if (NULL == p->tg)
115   {
116     GNUNET_break (0);
117     return;
118   }
119   delay = get_delay (p->tg);
120   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
121               "Delay for next transmission %s\n",
122               GNUNET_STRINGS_relative_time_to_string (delay,
123                                                       GNUNET_YES));
124   p->tg->next_ping_transmission
125     = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
126                                 delay);
127 }
128
129
130 static void
131 comm_schedule_send (void *cls)
132 {
133   struct BenchmarkPartner *p = cls;
134   struct TestMessage *msg;
135   struct GNUNET_MQ_Envelope *env;
136
137   p->tg->send_task = NULL;
138   p->last_message_sent = GNUNET_TIME_absolute_get();
139   env = GNUNET_MQ_msg (msg,
140                        TEST_MESSAGE_TYPE_PING);
141   memset (msg->padding,
142           'a',
143           sizeof (msg->padding));
144   GNUNET_MQ_notify_sent (env,
145                          &update_ping_data,
146                          p);
147   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
148               "Master [%u]: Sending PING to [%u]\n",
149               p->me->no,
150               p->dest->no);
151   GNUNET_MQ_send (p->mq,
152                   env);
153 }
154
155
156 static void
157 update_pong_data (void *cls)
158 {
159   struct BenchmarkPartner *p = cls;
160
161   p->messages_sent++;
162   p->bytes_sent += TEST_MESSAGE_SIZE;
163   p->me->total_messages_sent++;
164   p->me->total_bytes_sent += TEST_MESSAGE_SIZE;
165 }
166
167
168 void
169 GNUNET_ATS_TEST_traffic_handle_ping (struct BenchmarkPartner *p)
170 {
171   struct TestMessage *msg;
172   struct GNUNET_MQ_Envelope *env;
173
174   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
175               "Slave [%u]: Received PING from [%u], sending PONG\n",
176               p->me->no,
177               p->dest->no);
178   p->messages_received++;
179   p->bytes_received += TEST_MESSAGE_SIZE;
180   p->me->total_messages_received++;
181   p->me->total_bytes_received += TEST_MESSAGE_SIZE;
182
183   
184   env = GNUNET_MQ_msg (msg,
185                        TEST_MESSAGE_TYPE_PING);
186   memset (msg->padding,
187           'a',
188           sizeof (msg->padding));
189   GNUNET_MQ_notify_sent (env,
190                          &update_pong_data,
191                          p);
192   GNUNET_MQ_send (p->mq,
193                   env);
194 }
195
196
197 void
198 GNUNET_ATS_TEST_traffic_handle_pong (struct BenchmarkPartner *p)
199 {
200   struct GNUNET_TIME_Relative left;
201   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
202               "Master [%u]: Received PONG from [%u], next message\n",
203               p->me->no,
204               p->dest->no);
205
206   p->messages_received++;
207   p->bytes_received += TEST_MESSAGE_SIZE;
208   p->me->total_messages_received++;
209   p->me->total_bytes_received += TEST_MESSAGE_SIZE;
210   p->total_app_rtt += GNUNET_TIME_absolute_get_difference(p->last_message_sent,
211       GNUNET_TIME_absolute_get()).rel_value_us;
212
213   /* Schedule next send event */
214   if (NULL == p->tg)
215     return;
216
217   left = GNUNET_TIME_absolute_get_remaining(p->tg->next_ping_transmission);
218   if (UINT32_MAX == p->tg->base_rate)
219   {
220     p->tg->send_task = GNUNET_SCHEDULER_add_now (&comm_schedule_send, p);
221   }
222   else if (0 == left.rel_value_us)
223   {
224     p->tg->send_task = GNUNET_SCHEDULER_add_now (&comm_schedule_send, p);
225   }
226   else
227   {
228     /* Enforce minimum transmission rate 1 msg / sec */
229     if (GNUNET_TIME_UNIT_SECONDS.rel_value_us == (left = GNUNET_TIME_relative_min (left, GNUNET_TIME_UNIT_SECONDS)).rel_value_us)
230       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
231           "Enforcing minimum send rate between master [%u] and slave [%u]\n",
232           p->me->no, p->dest->no);
233     p->tg->send_task = GNUNET_SCHEDULER_add_delayed (left,
234         &comm_schedule_send, p);
235   }
236 }
237
238
239 /**
240  * Generate between the source master and the partner and send traffic with a
241  * maximum rate.
242  *
243  * @param src traffic source
244  * @param dest traffic partner
245  * @param type type of traffic to generate
246  * @param base_rate traffic base rate to send data with
247  * @param max_rate  traffic maximum rate to send data with
248  * @param period duration of a period of traffic generation (~ 1/frequency)
249  * @param duration how long to generate traffic
250  * @return the traffic generator
251  */
252 struct TrafficGenerator *
253 GNUNET_ATS_TEST_generate_traffic_start (struct BenchmarkPeer *src,
254                                         struct BenchmarkPartner *dest,
255                                         enum GeneratorType type,
256                                         unsigned int base_rate,
257                                         unsigned int max_rate,
258                                         struct GNUNET_TIME_Relative period,
259                                         struct GNUNET_TIME_Relative duration)
260 {
261   struct TrafficGenerator *tg;
262
263   if (NULL != dest->tg)
264   {
265     GNUNET_break (0);
266     return NULL;
267   }
268
269   tg = GNUNET_new (struct TrafficGenerator);
270   GNUNET_CONTAINER_DLL_insert (tg_head,
271                                tg_tail,
272                                tg);
273   tg->type = type;
274   tg->src = src;
275   tg->dest = dest;
276   tg->base_rate = base_rate;
277   tg->max_rate = max_rate;
278   tg->duration_period = period;
279   tg->time_start = GNUNET_TIME_absolute_get();
280   tg->next_ping_transmission = GNUNET_TIME_UNIT_FOREVER_ABS;
281
282   switch (type) {
283   case GNUNET_ATS_TEST_TG_CONSTANT:
284     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
285                 "Setting up constant traffic generator master[%u] `%s' and slave [%u] `%s' max %u Bips\n",
286                 dest->me->no,
287                 GNUNET_i2s (&dest->me->id),
288                 dest->dest->no,
289                 GNUNET_i2s (&dest->dest->id),
290                 base_rate);
291     break;
292   case GNUNET_ATS_TEST_TG_LINEAR:
293     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
294                 "Setting up linear traffic generator master[%u] `%s' and slave [%u] `%s' min %u Bips max %u Bips\n",
295                 dest->me->no,
296                 GNUNET_i2s (&dest->me->id),
297                 dest->dest->no,
298                 GNUNET_i2s (&dest->dest->id),
299                 base_rate,
300                 max_rate);
301     break;
302   case GNUNET_ATS_TEST_TG_SINUS:
303     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
304                 "Setting up sinus traffic generator master[%u] `%s' and slave [%u] `%s' baserate %u Bips, amplitude %u Bps\n",
305                 dest->me->no,
306                 GNUNET_i2s (&dest->me->id),
307                 dest->dest->no,
308                 GNUNET_i2s (&dest->dest->id),
309                 base_rate,
310                 max_rate);
311     break;
312   case GNUNET_ATS_TEST_TG_RANDOM:
313     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
314                 "Setting up random traffic generator master[%u] `%s' and slave [%u] `%s' min %u Bips max %u Bps\n",
315                 dest->me->no,
316                 GNUNET_i2s (&dest->me->id),
317                 dest->dest->no,
318                 GNUNET_i2s (&dest->dest->id),
319                 base_rate,
320                 max_rate);
321       break;
322     default:
323       break;
324   }
325
326   dest->tg = tg;
327   tg->send_task
328     = GNUNET_SCHEDULER_add_now (&comm_schedule_send,
329                                 dest);
330   return tg;
331 }
332
333
334 void
335 GNUNET_ATS_TEST_generate_traffic_stop (struct TrafficGenerator *tg)
336 {
337   GNUNET_CONTAINER_DLL_remove (tg_head,
338                                tg_tail,
339                                tg);
340   tg->dest->tg = NULL;
341   if (NULL != tg->send_task)
342   {
343     GNUNET_SCHEDULER_cancel (tg->send_task);
344     tg->send_task = NULL;
345   }
346   GNUNET_free (tg);
347 }
348
349
350 /**
351  * Stop all traffic generators
352  */
353 void
354 GNUNET_ATS_TEST_generate_traffic_stop_all ()
355 {
356   struct TrafficGenerator *cur;
357   struct TrafficGenerator *next;
358
359   next = tg_head;
360   for (cur = next; NULL != cur; cur = next)
361   {
362     next = cur->next;
363     GNUNET_ATS_TEST_generate_traffic_stop(cur);
364   }
365 }
366
367 /* end of file ats-testing-traffic.c */