]> git.ipfire.org Git - thirdparty/bird.git/blame - proto/perf/perf.c
Formalized our contribution policy which we're currently applying
[thirdparty/bird.git] / proto / perf / perf.c
CommitLineData
82b74253
MM
1/*
2 * BIRD -- Table-to-Table Routing Protocol a.k.a Pipe
3 *
4 * (c) 1999--2000 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9/**
10 * DOC: Perf
11 *
12 * Run this protocol to measure route import and export times.
13 * Generates a load of dummy routes and measures time to import.
14 */
15
16#undef LOCAL_DEBUG
17
18#include "nest/bird.h"
19#include "nest/iface.h"
20#include "nest/protocol.h"
21#include "nest/route.h"
22#include "nest/cli.h"
23#include "conf/conf.h"
24#include "filter/filter.h"
25#include "lib/string.h"
26
27#include "perf.h"
28
29#include <stdlib.h>
30#include <time.h>
31
7411b694 32#define PLOG(msg, ...) log(L_INFO "Perf %s %s " msg, BIRD_VERSION, p->p.name, ##__VA_ARGS__)
82b74253
MM
33
34static inline void
35random_data(void *p, uint len)
36{
37 uint ints = (len + sizeof(int) - 1) / sizeof(int);
38 int *d = alloca(sizeof(uint) * ints);
39 for (uint i=0; i<ints; i++)
40 d[i] = random();
41
42 memcpy(p, d, len);
43}
44
45static ip_addr
46random_gw(net_addr *prefix)
47{
48 ASSERT(net_is_ip(prefix));
49 ip_addr px = net_prefix(prefix);
50 ip_addr mask = net_pxmask(prefix);
51
52 ip_addr out;
53 random_data(&out, sizeof(ip_addr));
54
55 if (ipa_is_ip4(px))
56 out = ipa_and(out, ipa_from_ip4(ip4_mkmask(32)));
57
58 return ipa_or(ipa_and(px, mask), ipa_and(out, ipa_not(mask)));
59}
60
61static net_addr_ip4
62random_net_ip4(void)
63{
64 u32 x; random_data(&x, sizeof(u32));
65 x &= ((1 << 20) - 1);
66 uint pxlen = u32_log2(x) + 5;
67
68 ip4_addr px; random_data(&px, sizeof(ip4_addr));
69
70 net_addr_ip4 out = {
71 .type = NET_IP4,
72 .pxlen = pxlen,
73 .length = sizeof(net_addr_ip4),
74 .prefix = ip4_and(ip4_mkmask(pxlen), px),
75 };
76
77 if (!net_validate((net_addr *) &out))
78 return random_net_ip4();
79
80 int c = net_classify((net_addr *) &out);
81 if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
82 return random_net_ip4();
83
84 return out;
85}
86
87struct perf_random_routes {
dc042d87 88 struct rta *a;
82b74253 89 net_addr net;
82b74253
MM
90};
91
dc042d87 92//static const uint perf_random_routes_size = sizeof(struct perf_random_routes) + (RTA_MAX_SIZE - sizeof(struct rta));
2f02c25e 93
82b74253
MM
94static inline s64 timediff(struct timespec *begin, struct timespec *end)
95{ return (end->tv_sec - begin->tv_sec) * (s64) 1000000000 + end->tv_nsec - begin->tv_nsec; }
96
97static void
98perf_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
99{
100 struct perf_proto *p = (struct perf_proto *) P;
101
102 if (ad->flags & IA_SECONDARY)
103 return;
104
105 if (p->ifa && p->ifa == ad && (flags & IF_CHANGE_DOWN)) {
106 p->ifa = NULL;
107 if (ev_active(p->loop))
108 ev_postpone(p->loop);
109
110 return;
111 }
112
113 if (!p->ifa && (flags & IF_CHANGE_UP)) {
114 p->ifa = ad;
115 ev_schedule(p->loop);
116 PLOG("starting");
117 return;
118 }
119}
120
121static void
122perf_loop(void *data)
123{
124 struct proto *P = data;
125 struct perf_proto *p = data;
126
127 const uint N = 1U << p->exp;
82b74253
MM
128
129 if (!p->run) {
130 ASSERT(p->data == NULL);
dc042d87 131 p->data = xmalloc(sizeof(struct perf_random_routes) * N);
82b74253
MM
132 p->stop = 1;
133 }
134
135 ip_addr gw = random_gw(&p->ifa->prefix);
136
6dda6931 137 struct timespec ts_begin, ts_generated, ts_update, ts_withdraw;
82b74253
MM
138
139 clock_gettime(CLOCK_MONOTONIC, &ts_begin);
140
141 for (uint i=0; i<N; i++) {
dc042d87 142 *((net_addr_ip4 *) &(p->data[i].net)) = random_net_ip4();
82b74253 143
6dda6931 144 if (!p->attrs_per_rte || !(i % p->attrs_per_rte)) {
dc042d87 145 struct rta a0 = {
dc042d87
MM
146 .source = RTS_PERF,
147 .scope = SCOPE_UNIVERSE,
148 .dest = RTD_UNICAST,
eb937358 149 .pref = p->p.main_channel->preference,
dc042d87
MM
150 .nh.iface = p->ifa->iface,
151 .nh.gw = gw,
152 .nh.weight = 1,
153 };
154
155 p->data[i].a = rta_lookup(&a0);
6dda6931 156 }
dc042d87
MM
157 else
158 p->data[i].a = rta_clone(p->data[i-1].a);
82b74253
MM
159 }
160
6dda6931 161 clock_gettime(CLOCK_MONOTONIC, &ts_generated);
82b74253
MM
162
163 for (uint i=0; i<N; i++) {
5cff1d5f 164 rte *e = rte_get_temp(p->data[i].a, p->p.main_source);
dc042d87
MM
165
166 rte_update(P, &(p->data[i].net), e);
82b74253
MM
167 }
168
169 clock_gettime(CLOCK_MONOTONIC, &ts_update);
170
171 if (!p->keep)
dc042d87
MM
172 for (uint i=0; i<N; i++)
173 rte_update(P, &(p->data[i].net), NULL);
82b74253
MM
174
175 clock_gettime(CLOCK_MONOTONIC, &ts_withdraw);
176
177 s64 gentime = timediff(&ts_begin, &ts_generated);
6dda6931 178 s64 updatetime = timediff(&ts_generated, &ts_update);
82b74253
MM
179 s64 withdrawtime = timediff(&ts_update, &ts_withdraw);
180
181 if (updatetime NS >= p->threshold_min)
759b204b 182 PLOG("exp=%u times: gen=%ld update=%ld withdraw=%ld",
6dda6931 183 p->exp, gentime, updatetime, withdrawtime);
82b74253
MM
184
185 if (updatetime NS < p->threshold_max)
186 p->stop = 0;
187
188 if ((updatetime NS < p->threshold_min) || (++p->run == p->repeat)) {
189 xfree(p->data);
190 p->data = NULL;
191
192 if (p->stop || (p->exp == p->to)) {
193 PLOG("done with exp=%u", p->exp);
194 return;
195 }
196
197 p->run = 0;
198 p->exp++;
199 }
200
e85e37d9 201 rt_schedule_prune(P->main_channel->table);
82b74253
MM
202 ev_schedule(p->loop);
203}
204
205static void
206perf_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net UNUSED, struct rte *new UNUSED, struct rte *old UNUSED)
207{
208 struct perf_proto *p = (struct perf_proto *) P;
209 p->exp++;
210 return;
211}
212
213static void
214perf_feed_begin(struct channel *c, int initial UNUSED)
215{
216 struct perf_proto *p = (struct perf_proto *) c->proto;
217
218 p->run++;
dc042d87 219 p->feed_begin = xmalloc(sizeof(struct timespec));
82b74253
MM
220 p->exp = 0;
221
dc042d87 222 clock_gettime(CLOCK_MONOTONIC, p->feed_begin);
82b74253
MM
223}
224
225static void
226perf_feed_end(struct channel *c)
227{
228 struct perf_proto *p = (struct perf_proto *) c->proto;
229 struct timespec ts_end;
230 clock_gettime(CLOCK_MONOTONIC, &ts_end);
231
dc042d87 232 s64 feedtime = timediff(p->feed_begin, &ts_end);
82b74253
MM
233
234 PLOG("feed n=%lu time=%lu", p->exp, feedtime);
235
dc042d87
MM
236 xfree(p->feed_begin);
237 p->feed_begin = NULL;
238
82b74253
MM
239 if (p->run < p->repeat)
240 channel_request_feeding(c);
241 else
242 PLOG("feed done");
243}
244
245static struct proto *
246perf_init(struct proto_config *CF)
247{
248 struct proto *P = proto_new(CF);
249
250 P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
251
252 struct perf_proto *p = (struct perf_proto *) P;
253
254 p->loop = ev_new_init(P->pool, perf_loop, p);
255
256 struct perf_config *cf = (struct perf_config *) CF;
257
258 p->threshold_min = cf->threshold_min;
259 p->threshold_max = cf->threshold_max;
260 p->from = cf->from;
261 p->to = cf->to;
262 p->repeat = cf->repeat;
263 p->keep = cf->keep;
264 p->mode = cf->mode;
6dda6931 265 p->attrs_per_rte = cf->attrs_per_rte;
82b74253
MM
266
267 switch (p->mode) {
268 case PERF_MODE_IMPORT:
269 P->ifa_notify = perf_ifa_notify;
270 break;
271 case PERF_MODE_EXPORT:
272 P->rt_notify = perf_rt_notify;
273 P->feed_begin = perf_feed_begin;
274 P->feed_end = perf_feed_end;
275 break;
276 }
277
278 return P;
279}
280
281static int
282perf_start(struct proto *P)
283{
284 struct perf_proto *p = (struct perf_proto *) P;
285
286 p->ifa = NULL;
287 p->run = 0;
288 p->exp = p->from;
289 ASSERT(p->data == NULL);
290
291 return PS_UP;
292}
293
294static int
295perf_reconfigure(struct proto *P UNUSED, struct proto_config *CF UNUSED)
296{
297 return 0;
298}
299
300static void
301perf_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
302{
303}
304
305struct protocol proto_perf = {
306 .name = "Perf",
307 .template = "perf%d",
308 .class = PROTOCOL_PERF,
309 .channel_mask = NB_IP,
310 .proto_size = sizeof(struct perf_proto),
311 .config_size = sizeof(struct perf_config),
312 .init = perf_init,
313 .start = perf_start,
314 .reconfigure = perf_reconfigure,
315 .copy_config = perf_copy_config,
316};
4a23ede2
MM
317
318void
319perf_build(void)
320{
321 proto_build(&proto_perf);
322}