]> git.ipfire.org Git - thirdparty/bird.git/blame - test/bt-utils.c
Doc: BFD update
[thirdparty/bird.git] / test / bt-utils.c
CommitLineData
9b0a0ba9
OZ
1/*
2 * BIRD Test -- Utils for testing parsing configuration file
3 *
4 * (c) 2015 CZ.NIC z.s.p.o.
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9#include <stdlib.h>
10#include <fcntl.h>
11#include <unistd.h>
12
13#include "test/birdtest.h"
14#include "test/bt-utils.h"
15
16#include "nest/bird.h"
17#include "nest/route.h"
18#include "nest/protocol.h"
e55696a4 19#include "nest/mpls.h"
9b0a0ba9
OZ
20
21#include "sysdep/unix/unix.h"
22#include "sysdep/unix/krt.h"
23
24#include "nest/iface.h"
25#include "nest/locks.h"
26
27#include "filter/filter.h"
28
29#define BETWEEN(a, b, c) (((a) >= (b)) && ((a) <= (c)))
30
31static const byte *bt_config_parse_pos;
32static uint bt_config_parse_remain_len;
33
34/* This is cf_read_hook for hard-coded text configuration */
35static int
36cf_static_read(byte *dest, uint max_len, int fd UNUSED)
37{
38 if (max_len > bt_config_parse_remain_len)
39 max_len = bt_config_parse_remain_len;
40 memcpy(dest, bt_config_parse_pos, max_len);
41 bt_config_parse_pos += max_len;
42 bt_config_parse_remain_len -= max_len;
43 return max_len;
44}
45
46/* This is cf_read_hook for reading configuration files,
47 * function is copied from main.c, cf_read() */
48static int
49cf_file_read(byte *dest, uint max_len, int fd)
50{
51 int l = read(fd, dest, max_len);
52 if (l < 0)
53 cf_error("Read error");
54 return l;
55}
56
57void
58bt_bird_init(void)
59{
60 if(bt_verbose)
61 log_init_debug("");
62 log_switch(bt_verbose != 0, NULL, NULL);
63
9b0a0ba9 64 olock_init();
212eda07 65 timer_init();
9b0a0ba9
OZ
66 io_init();
67 rt_init();
68 if_init();
333ddd4f 69 mpls_init();
9b0a0ba9
OZ
70 config_init();
71
72 protos_build();
9b0a0ba9
OZ
73}
74
75void bt_bird_cleanup(void)
76{
ee7e2ffd
JMM
77 for (int i = 0; i < PROTOCOL__MAX; i++)
78 class_to_protocol[i] = NULL;
9b0a0ba9
OZ
79
80 config = new_config = NULL;
81}
82
83static char *
84bt_load_file(const char *filename, int quiet)
85{
86 FILE *f = fopen(filename, "rb");
87 if (!quiet)
88 bt_assert_msg(f != NULL, "Open %s", filename);
89
90 if (f == NULL)
91 return NULL;
92
93 fseek(f, 0, SEEK_END);
94 long file_size_ = ftell(f);
95 fseek(f, 0, SEEK_SET);
96
97 if (file_size_ < 0)
98 return NULL;
99
100 size_t file_size = file_size_;
101 size_t read_size = 0;
102
103 char *file_body = mb_allocz(&root_pool, file_size+1);
104
105 /* XXX: copied from cf-lex.c */
106 errno=0;
107 while ((read_size += fread(file_body+read_size, 1, file_size-read_size, f)) != file_size && ferror(f))
108 {
109 bt_debug("iteration \n");
110 if(errno != EINTR)
111 {
112 bt_abort_msg("errno: %d", errno);
113 break;
114 }
115 errno=0;
116 clearerr(f);
117 }
118 fclose(f);
119
120 if (!quiet)
121 bt_assert_msg(read_size == file_size, "Read %s", filename);
122
123 return file_body;
124}
125
126static void
127bt_show_cfg_error(const struct config *cfg)
128{
129 int lino = 0;
130 int lino_delta = 5;
131 int lino_err = cfg->err_lino;
132
133 const char *str = bt_load_file(cfg->err_file_name, 1);
134
135 while (str && *str)
136 {
137 lino++;
138 if (BETWEEN(lino, lino_err - lino_delta, lino_err + lino_delta))
139 bt_debug("%4u%s", lino, (lino_err == lino ? " >> " : " "));
140 do
141 {
142 if (BETWEEN(lino, lino_err - lino_delta, lino_err + lino_delta))
143 bt_debug("%c", *str);
144 } while (*str && *(str++) != '\n');
145 }
146 bt_debug("\n");
147}
148
149static struct config *
150bt_config_parse__(struct config *cfg)
151{
152 bt_assert_msg(config_parse(cfg) == 1, "Parse %s", cfg->file_name);
153
154 if (cfg->err_msg)
155 {
3dabf7b8 156 bt_log("Parse error %s, line %d: %s", cfg->err_file_name, cfg->err_lino, cfg->err_msg);
9b0a0ba9
OZ
157 bt_show_cfg_error(cfg);
158 return NULL;
159 }
160
161 config_commit(cfg, RECONFIG_HARD, 0);
162 new_config = cfg;
163
164 return cfg;
165}
166
167struct config *
168bt_config_parse(const char *cfg_str)
169{
170 struct config *cfg = config_alloc("configuration");
171
172 bt_config_parse_pos = cfg_str;
173 bt_config_parse_remain_len = strlen(cfg_str);
174 cf_read_hook = cf_static_read;
175
176 return bt_config_parse__(cfg);
177}
178
179struct config *
180bt_config_file_parse(const char *filepath)
181{
182 struct config *cfg = config_alloc(filepath);
183
184 cfg->file_fd = open(filepath, O_RDONLY);
185 bt_assert_msg(cfg->file_fd > 0, "Open %s", filepath);
186 if (cfg->file_fd < 0)
187 return NULL;
188
189 cf_read_hook = cf_file_read;
190
191 return bt_config_parse__(cfg);
192}
193
194/*
195 * Returns @base raised to the power of @power.
196 */
197uint
198bt_naive_pow(uint base, uint power)
199{
200 uint result = 1;
201 uint i;
202 for (i = 0; i < power; i++)
203 result *= base;
204 return result;
205}
206
207/**
208 * bytes_to_hex - transform data into hexadecimal representation
209 * @buf: preallocated string buffer
210 * @in_data: data for transformation
211 * @size: the length of @in_data
212 *
213 * This function transforms @in_data of length @size into hexadecimal
214 * representation and writes it into @buf.
215 */
216void
217bt_bytes_to_hex(char *buf, const byte *in_data, size_t size)
218{
219 size_t i;
220 for(i = 0; i < size; i++)
221 sprintf(buf + i*2, "%02x", in_data[i]);
222}
223
3cf91fb9
OZ
224void
225bt_random_net(net_addr *net, int type)
226{
227 ip4_addr ip4;
228 ip6_addr ip6;
229 uint pxlen;
230
231 switch (type)
232 {
233 case NET_IP4:
234 pxlen = bt_random_n(24)+8;
235 ip4 = ip4_from_u32((u32) bt_random());
236 net_fill_ip4(net, ip4_and(ip4, ip4_mkmask(pxlen)), pxlen);
237 break;
238
239 case NET_IP6:
240 pxlen = bt_random_n(120)+8;
241 ip6 = ip6_build(bt_random(), bt_random(), bt_random(), bt_random());
242 net_fill_ip6(net, ip6_and(ip6, ip6_mkmask(pxlen)), pxlen);
243 break;
244
245 default:
246 die("Net type %d not implemented", type);
247 }
248}
249
250net_addr *
251bt_random_nets(int type, uint n)
252{
253 net_addr *nets = tmp_alloc(n * sizeof(net_addr));
254
255 for (uint i = 0; i < n; i++)
256 bt_random_net(&nets[i], type);
257
258 return nets;
259}
260
261net_addr *
262bt_random_net_subset(net_addr *src, uint sn, uint dn)
263{
264 net_addr *nets = tmp_alloc(dn * sizeof(net_addr));
265
266 for (uint i = 0; i < dn; i++)
267 net_copy(&nets[i], &src[bt_random_n(sn)]);
268
269 return nets;
270}
271
272void
273bt_read_net(const char *str, net_addr *net, int type)
274{
275 ip4_addr ip4;
276 ip6_addr ip6;
277 uint pxlen;
278 char addr[64];
279
280 switch (type)
281 {
282 case NET_IP4:
283 if (sscanf(str, "%[0-9.]/%u", addr, &pxlen) != 2)
284 goto err;
285
286 if (!ip4_pton(addr, &ip4))
287 goto err;
288
289 if (!net_validate_px4(ip4, pxlen))
290 goto err;
291
292 net_fill_ip4(net, ip4, pxlen);
293 break;
294
295 case NET_IP6:
296 if (sscanf(str, "%[0-9a-fA-F:.]/%u", addr, &pxlen) != 2)
297 goto err;
298
299 if (!ip6_pton(addr, &ip6))
300 goto err;
301
302 if (!net_validate_px6(ip6, pxlen))
303 goto err;
304
305 net_fill_ip6(net, ip6, pxlen);
306 break;
307
308 default:
309 die("Net type %d not implemented", type);
310 }
311 return;
312
313err:
314 bt_abort_msg("Invalid network '%s'", str);
315}
316
317net_addr *
318bt_read_nets(FILE *f, int type, uint *n)
319{
320 char str[80];
321
322 net_addr *nets = tmp_alloc(*n * sizeof(net_addr));
323 uint i = 0;
324
325 errno = 0;
326 while (fgets(str, sizeof(str), f))
327 {
328 if (str[0] == '\n')
329 break;
330
331 if (i >= *n)
332 bt_abort_msg("Too many networks");
333
334 bt_read_net(str, &nets[i], type);
335 bt_debug("ADD %s\n", str);
336 i++;
337 }
338 bt_syscall(errno, "fgets()");
339
340 bt_debug("DONE reading %u nets\n", i);
341
342 *n = i;
343 return nets;
344}
345
346net_addr *
347bt_read_net_file(const char *filename, int type, uint *n)
348{
349 FILE *f = fopen(filename, "r");
350 bt_syscall(!f, "fopen(%s)", filename);
351 net_addr *nets = bt_read_nets(f, type, n);
352 fclose(f);
353
354 return nets;
355}