mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-17 16:48:43 +00:00
333ddd4f98
The MPLS subsystem manages MPLS labels and handles their allocation to MPLS-aware routing protocols. These labels are then attached to IP or VPN routes representing label switched paths -- LSPs. There was already a preliminary MPLS support consisting of MPLS label net_addr, MPLS routing tables with static MPLS routes, remote labels in next hops, and kernel protocol support. This patch adds the MPLS domain as a basic structure representing local label space with dynamic label allocator and configurable label ranges. To represent LSPs, allocated local labels can be attached as route attributes to IP or VPN routes with local labels as attributes. There are several steps for handling LSP routes in routing protocols -- deciding to which forwarding equivalence class (FEC) the LSP route belongs, allocating labels for new FECs, announcing MPLS routes for new FECs, attaching labels to LSP routes. The FEC map structure implements basic code for managing FECs in routing protocols, therefore existing protocols can be made MPLS-aware by adding FEC map and delegating most work related to local label management to it.
356 lines
6.9 KiB
C
356 lines
6.9 KiB
C
/*
|
|
* BIRD Test -- Utils for testing parsing configuration file
|
|
*
|
|
* (c) 2015 CZ.NIC z.s.p.o.
|
|
*
|
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
#include "test/birdtest.h"
|
|
#include "test/bt-utils.h"
|
|
|
|
#include "nest/bird.h"
|
|
#include "nest/route.h"
|
|
#include "nest/protocol.h"
|
|
#include "nest/mpls.h"
|
|
|
|
#include "sysdep/unix/unix.h"
|
|
#include "sysdep/unix/krt.h"
|
|
|
|
#include "nest/iface.h"
|
|
#include "nest/locks.h"
|
|
|
|
#include "filter/filter.h"
|
|
|
|
#define BETWEEN(a, b, c) (((a) >= (b)) && ((a) <= (c)))
|
|
|
|
static const byte *bt_config_parse_pos;
|
|
static uint bt_config_parse_remain_len;
|
|
|
|
/* This is cf_read_hook for hard-coded text configuration */
|
|
static int
|
|
cf_static_read(byte *dest, uint max_len, int fd UNUSED)
|
|
{
|
|
if (max_len > bt_config_parse_remain_len)
|
|
max_len = bt_config_parse_remain_len;
|
|
memcpy(dest, bt_config_parse_pos, max_len);
|
|
bt_config_parse_pos += max_len;
|
|
bt_config_parse_remain_len -= max_len;
|
|
return max_len;
|
|
}
|
|
|
|
/* This is cf_read_hook for reading configuration files,
|
|
* function is copied from main.c, cf_read() */
|
|
static int
|
|
cf_file_read(byte *dest, uint max_len, int fd)
|
|
{
|
|
int l = read(fd, dest, max_len);
|
|
if (l < 0)
|
|
cf_error("Read error");
|
|
return l;
|
|
}
|
|
|
|
void
|
|
bt_bird_init(void)
|
|
{
|
|
if(bt_verbose)
|
|
log_init_debug("");
|
|
log_switch(bt_verbose != 0, NULL, NULL);
|
|
|
|
olock_init();
|
|
timer_init();
|
|
io_init();
|
|
rt_init();
|
|
if_init();
|
|
mpls_init();
|
|
config_init();
|
|
|
|
protos_build();
|
|
}
|
|
|
|
void bt_bird_cleanup(void)
|
|
{
|
|
for (int i = 0; i < PROTOCOL__MAX; i++)
|
|
class_to_protocol[i] = NULL;
|
|
|
|
config = new_config = NULL;
|
|
}
|
|
|
|
static char *
|
|
bt_load_file(const char *filename, int quiet)
|
|
{
|
|
FILE *f = fopen(filename, "rb");
|
|
if (!quiet)
|
|
bt_assert_msg(f != NULL, "Open %s", filename);
|
|
|
|
if (f == NULL)
|
|
return NULL;
|
|
|
|
fseek(f, 0, SEEK_END);
|
|
long file_size_ = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
if (file_size_ < 0)
|
|
return NULL;
|
|
|
|
size_t file_size = file_size_;
|
|
size_t read_size = 0;
|
|
|
|
char *file_body = mb_allocz(&root_pool, file_size+1);
|
|
|
|
/* XXX: copied from cf-lex.c */
|
|
errno=0;
|
|
while ((read_size += fread(file_body+read_size, 1, file_size-read_size, f)) != file_size && ferror(f))
|
|
{
|
|
bt_debug("iteration \n");
|
|
if(errno != EINTR)
|
|
{
|
|
bt_abort_msg("errno: %d", errno);
|
|
break;
|
|
}
|
|
errno=0;
|
|
clearerr(f);
|
|
}
|
|
fclose(f);
|
|
|
|
if (!quiet)
|
|
bt_assert_msg(read_size == file_size, "Read %s", filename);
|
|
|
|
return file_body;
|
|
}
|
|
|
|
static void
|
|
bt_show_cfg_error(const struct config *cfg)
|
|
{
|
|
int lino = 0;
|
|
int lino_delta = 5;
|
|
int lino_err = cfg->err_lino;
|
|
|
|
const char *str = bt_load_file(cfg->err_file_name, 1);
|
|
|
|
while (str && *str)
|
|
{
|
|
lino++;
|
|
if (BETWEEN(lino, lino_err - lino_delta, lino_err + lino_delta))
|
|
bt_debug("%4u%s", lino, (lino_err == lino ? " >> " : " "));
|
|
do
|
|
{
|
|
if (BETWEEN(lino, lino_err - lino_delta, lino_err + lino_delta))
|
|
bt_debug("%c", *str);
|
|
} while (*str && *(str++) != '\n');
|
|
}
|
|
bt_debug("\n");
|
|
}
|
|
|
|
static struct config *
|
|
bt_config_parse__(struct config *cfg)
|
|
{
|
|
bt_assert_msg(config_parse(cfg) == 1, "Parse %s", cfg->file_name);
|
|
|
|
if (cfg->err_msg)
|
|
{
|
|
bt_log("Parse error %s, line %d: %s", cfg->err_file_name, cfg->err_lino, cfg->err_msg);
|
|
bt_show_cfg_error(cfg);
|
|
return NULL;
|
|
}
|
|
|
|
config_commit(cfg, RECONFIG_HARD, 0);
|
|
new_config = cfg;
|
|
|
|
return cfg;
|
|
}
|
|
|
|
struct config *
|
|
bt_config_parse(const char *cfg_str)
|
|
{
|
|
struct config *cfg = config_alloc("configuration");
|
|
|
|
bt_config_parse_pos = cfg_str;
|
|
bt_config_parse_remain_len = strlen(cfg_str);
|
|
cf_read_hook = cf_static_read;
|
|
|
|
return bt_config_parse__(cfg);
|
|
}
|
|
|
|
struct config *
|
|
bt_config_file_parse(const char *filepath)
|
|
{
|
|
struct config *cfg = config_alloc(filepath);
|
|
|
|
cfg->file_fd = open(filepath, O_RDONLY);
|
|
bt_assert_msg(cfg->file_fd > 0, "Open %s", filepath);
|
|
if (cfg->file_fd < 0)
|
|
return NULL;
|
|
|
|
cf_read_hook = cf_file_read;
|
|
|
|
return bt_config_parse__(cfg);
|
|
}
|
|
|
|
/*
|
|
* Returns @base raised to the power of @power.
|
|
*/
|
|
uint
|
|
bt_naive_pow(uint base, uint power)
|
|
{
|
|
uint result = 1;
|
|
uint i;
|
|
for (i = 0; i < power; i++)
|
|
result *= base;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* bytes_to_hex - transform data into hexadecimal representation
|
|
* @buf: preallocated string buffer
|
|
* @in_data: data for transformation
|
|
* @size: the length of @in_data
|
|
*
|
|
* This function transforms @in_data of length @size into hexadecimal
|
|
* representation and writes it into @buf.
|
|
*/
|
|
void
|
|
bt_bytes_to_hex(char *buf, const byte *in_data, size_t size)
|
|
{
|
|
size_t i;
|
|
for(i = 0; i < size; i++)
|
|
sprintf(buf + i*2, "%02x", in_data[i]);
|
|
}
|
|
|
|
void
|
|
bt_random_net(net_addr *net, int type)
|
|
{
|
|
ip4_addr ip4;
|
|
ip6_addr ip6;
|
|
uint pxlen;
|
|
|
|
switch (type)
|
|
{
|
|
case NET_IP4:
|
|
pxlen = bt_random_n(24)+8;
|
|
ip4 = ip4_from_u32((u32) bt_random());
|
|
net_fill_ip4(net, ip4_and(ip4, ip4_mkmask(pxlen)), pxlen);
|
|
break;
|
|
|
|
case NET_IP6:
|
|
pxlen = bt_random_n(120)+8;
|
|
ip6 = ip6_build(bt_random(), bt_random(), bt_random(), bt_random());
|
|
net_fill_ip6(net, ip6_and(ip6, ip6_mkmask(pxlen)), pxlen);
|
|
break;
|
|
|
|
default:
|
|
die("Net type %d not implemented", type);
|
|
}
|
|
}
|
|
|
|
net_addr *
|
|
bt_random_nets(int type, uint n)
|
|
{
|
|
net_addr *nets = tmp_alloc(n * sizeof(net_addr));
|
|
|
|
for (uint i = 0; i < n; i++)
|
|
bt_random_net(&nets[i], type);
|
|
|
|
return nets;
|
|
}
|
|
|
|
net_addr *
|
|
bt_random_net_subset(net_addr *src, uint sn, uint dn)
|
|
{
|
|
net_addr *nets = tmp_alloc(dn * sizeof(net_addr));
|
|
|
|
for (uint i = 0; i < dn; i++)
|
|
net_copy(&nets[i], &src[bt_random_n(sn)]);
|
|
|
|
return nets;
|
|
}
|
|
|
|
void
|
|
bt_read_net(const char *str, net_addr *net, int type)
|
|
{
|
|
ip4_addr ip4;
|
|
ip6_addr ip6;
|
|
uint pxlen;
|
|
char addr[64];
|
|
|
|
switch (type)
|
|
{
|
|
case NET_IP4:
|
|
if (sscanf(str, "%[0-9.]/%u", addr, &pxlen) != 2)
|
|
goto err;
|
|
|
|
if (!ip4_pton(addr, &ip4))
|
|
goto err;
|
|
|
|
if (!net_validate_px4(ip4, pxlen))
|
|
goto err;
|
|
|
|
net_fill_ip4(net, ip4, pxlen);
|
|
break;
|
|
|
|
case NET_IP6:
|
|
if (sscanf(str, "%[0-9a-fA-F:.]/%u", addr, &pxlen) != 2)
|
|
goto err;
|
|
|
|
if (!ip6_pton(addr, &ip6))
|
|
goto err;
|
|
|
|
if (!net_validate_px6(ip6, pxlen))
|
|
goto err;
|
|
|
|
net_fill_ip6(net, ip6, pxlen);
|
|
break;
|
|
|
|
default:
|
|
die("Net type %d not implemented", type);
|
|
}
|
|
return;
|
|
|
|
err:
|
|
bt_abort_msg("Invalid network '%s'", str);
|
|
}
|
|
|
|
net_addr *
|
|
bt_read_nets(FILE *f, int type, uint *n)
|
|
{
|
|
char str[80];
|
|
|
|
net_addr *nets = tmp_alloc(*n * sizeof(net_addr));
|
|
uint i = 0;
|
|
|
|
errno = 0;
|
|
while (fgets(str, sizeof(str), f))
|
|
{
|
|
if (str[0] == '\n')
|
|
break;
|
|
|
|
if (i >= *n)
|
|
bt_abort_msg("Too many networks");
|
|
|
|
bt_read_net(str, &nets[i], type);
|
|
bt_debug("ADD %s\n", str);
|
|
i++;
|
|
}
|
|
bt_syscall(errno, "fgets()");
|
|
|
|
bt_debug("DONE reading %u nets\n", i);
|
|
|
|
*n = i;
|
|
return nets;
|
|
}
|
|
|
|
net_addr *
|
|
bt_read_net_file(const char *filename, int type, uint *n)
|
|
{
|
|
FILE *f = fopen(filename, "r");
|
|
bt_syscall(!f, "fopen(%s)", filename);
|
|
net_addr *nets = bt_read_nets(f, type, n);
|
|
fclose(f);
|
|
|
|
return nets;
|
|
}
|