1
0
mirror of https://github.com/rtbrick/bngblaster.git synced 2024-05-06 15:54:57 +00:00
rtbrick-bngblaster/code/lspgen/src/lspgen_forest.c
Christian Giese 08d2f85975 Add LSPGEN and Restructure Project
+ restructure project
+ add lspgen
+ ...
2022-03-08 21:25:09 +01:00

264 lines
7.9 KiB
C

/*
* Generic Link State Packet generation for link-state protocols.
*
* Hannes Gredler, January 2022
*
* Copyright (C) 2015-2022, RtBrick, Inc.
*/
/*
* Graph generation code extracted from
*
* A Graph Generation Package
* Richard Johnsonbaugh and Martin Kalin
* Department of Computer Science and Information Systems
* DePaul University
* Chicago, IL 60604
* johnsonbaugh@cs.depaul.edu, kalin@cs.depaul.edu
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "lspgen.h"
#include "lspgen_lsdb.h"
int weights[13] = { 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000 };
/*
* Return a random integer between 0 and k-1 inclusive.
*/
int
ran(int k)
{
return rand() % k;
}
void
swap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
/*
* randomly permute a[ 0 ],...,a[ n - 1 ]
*/
void
permute(int *a, int n)
{
int i;
for (i = 0; i < n - 1; i++) {
swap(a + i + ran(n - i), a + i);
}
}
/*
* set a[ i ] = i, for i = 0,...,end - 1
*/
void
init_array(int *a, int end)
{
int i;
for (i = 0; i < end; i++) {
*a++ = i;
}
}
void
print_graph(lsdb_ctx_t *ctx, int v, int e, int *adj_matrix)
{
struct lsdb_node_ node_template;
struct lsdb_link_ link_template;
struct lsdb_node_ *local_node, *remote_node;
char node_name[32];
int i, j, index;
unsigned int root = 0;
__uint128_t addr;
UNUSED(e);
memset(&node_template, 0, sizeof(node_template));
memset(&link_template, 0, sizeof(link_template));
for (i = 1; i < v; i++) {
for (j = i + 1; j <= v; j++) {
index = (i - 1) * v + j - 1;
if (adj_matrix[index]) {
if (!root) {
root = i;
}
/*
* Add local node.
*/
addr = lspgen_load_addr((uint8_t*)&ctx->ipv4_node_prefix.address, sizeof(ipv4addr_t)) + i - 1;
lspgen_store_bcd_addr(addr, node_template.key.node_id, 4);
snprintf(node_name, sizeof(node_name), "node%u", i);
node_template.node_name = node_name;
local_node = lsdb_add_node(ctx, &node_template);
/*
* Add remote node.
*/
addr = lspgen_load_addr((uint8_t*)&ctx->ipv4_node_prefix.address, sizeof(ipv4addr_t)) + j - 1;
lspgen_store_bcd_addr(addr, node_template.key.node_id, 4);
snprintf(node_name, sizeof(node_name), "node%u", j);
node_template.node_name = node_name;
remote_node = lsdb_add_node(ctx, &node_template);
/*
* Add outgoing link.
*/
link_template.link_metric = weights[adj_matrix[index]];
addr = lspgen_load_addr((uint8_t*)&ctx->ipv4_node_prefix.address, sizeof(ipv4addr_t)) + i - 1;
lspgen_store_bcd_addr(addr, link_template.key.local_node_id, 4);
addr = lspgen_load_addr((uint8_t*)&ctx->ipv4_node_prefix.address, sizeof(ipv4addr_t)) + j - 1;
lspgen_store_bcd_addr(addr, link_template.key.remote_node_id, 4);
lsdb_add_link(ctx, local_node, &link_template);
/*
* Add incoming link.
*/
addr = lspgen_load_addr((uint8_t*)&ctx->ipv4_node_prefix.address, sizeof(ipv4addr_t)) + j - 1;
lspgen_store_bcd_addr(addr, link_template.key.local_node_id, 4);
addr = lspgen_load_addr((uint8_t*)&ctx->ipv4_node_prefix.address, sizeof(ipv4addr_t)) + i - 1;
lspgen_store_bcd_addr(addr, link_template.key.remote_node_id, 4);
lsdb_add_link(ctx, remote_node, &link_template);
}
}
}
/*
* Store root.
*/
addr = lspgen_load_addr((uint8_t*)&ctx->ipv4_node_prefix.address, sizeof(ipv4addr_t)) + root - 1;
lspgen_store_bcd_addr(addr, ctx->root_node_id, 4);
}
/*
* This function generates a random connected simple graph with v vertices and max(v-1,e) edges. The graph can be
* weighted (weight_flag == 1) or unweighted (weight_flag != 1). If it is weighted, the weights are in the range 1 to
* max_wgt. It is assumed that e <= v(v-1)/2. (In this program, this assured because of the call to
* fix_imbalanced_graph.)
*
* To generate a random connected graph, we begin by generating a random spanning tree. To generate a random spanning
* tree, we first generate a random permutation tree[0],...,tree[v-1]. (v = number of vertices.) We then iteratively
* add edges to form a tree. We begin with the tree consisting of vertex tree[0] and no edges. At the iterative step,
* we assume that tree[0],tree[1],...,tree[i-1] are in the tree. We then add vertex tree[i] to the tree by adding the
* edge (tree[i],tree[rand(i)]). (This construction is similar to that of Prim's algorithm.) Finally, we add random
* edges to produce the desired number of edges.
*/
static void
lsdb_random_connected_graph(lsdb_ctx_t *ctx, int v, int e, int max_wgt, int weight_flag)
{
int i, j, count, index, *adj_matrix, *tree;
LOG(NORMAL, "Generating a graph of %d nodes and %d links\n", v, e);
if ((adj_matrix = (int *) calloc(v * v, sizeof(int))) == NULL) {
LOG(ERROR, "Not enough room for %d nodes %d links graph\n", v, e);
return;
}
if ((tree = (int *) calloc(v, sizeof(int))) == NULL) {
LOG(ERROR, "Not enough room for %d nodes %d links graph\n", v, e);
free(adj_matrix);
return;
}
/*
* Generate a random permutation in the array tree.
*/
init_array(tree, v);
permute(tree, v);
/*
* Next generate a random spanning tree. The algorithm is:
*
* Assume that vertices tree[ 0 ],...,tree[ i - 1 ] are in the tree. Add an edge incident on tree[ i ] and a
* random vertex in the set {tree[ 0 ],...,tree[ i - 1 ]}.
*/
for (i = 1; i < v; i++) {
j = ran(i);
adj_matrix[tree[i] * v + tree[j]] = adj_matrix[tree[j] * v + tree[i]] = weight_flag ? 1 + ran(max_wgt) : 1;
}
/*
* Add additional random edges until achieving at least desired number
*/
for (count = v - 1; count < e;) {
i = ran(v);
j = ran(v);
if (i == j)
continue;
if (i > j)
swap(&i, &j);
index = i * v + j;
if (!adj_matrix[index]) {
adj_matrix[index] = weight_flag ? 1 + ran(max_wgt) : 1;
count++;
}
}
print_graph(ctx, v, count, adj_matrix);
free(tree);
free(adj_matrix);
}
void
lsdb_init_graph(lsdb_ctx_t *ctx)
{
struct lsdb_node_ node_template;
struct lsdb_link_ link_template;
struct lsdb_node_ *node;
uint32_t idx;
srand(ctx->seed);
lsdb_random_connected_graph(ctx, ctx->num_nodes, ctx->num_nodes << 1,
sizeof(weights) / sizeof(int) - 1, 1);
/*
* First lookup the root node.
*/
memset(&node_template, 0, sizeof(node_template));
memcpy(&node_template.key, ctx->root_node_id, sizeof(node_template.key));
node = lsdb_get_node(ctx, &node_template);
if (!node) {
LOG(ERROR, "Could not find root node %s\n", lsdb_format_node_id(node_template.key.node_id));
return;
}
LOG(NORMAL, " Root node %s\n", lsdb_format_node_id(node_template.key.node_id));
/*
* Add connectors to the topology
*/
if (ctx->num_connector) {
/*
* Next add outgoing edges from the root node.
*/
for (idx = 0; idx < ctx->num_connector; idx++) {
memset(&link_template, 0, sizeof(link_template));
memcpy(&link_template.key.local_node_id, ctx->root_node_id,
sizeof(link_template.key.local_node_id));
memcpy(&link_template.key.remote_node_id, ctx->connector[idx].node_id,
sizeof(link_template.key.remote_node_id));
link_template.link_metric = 100;
lsdb_add_link(ctx, node, &link_template);
}
}
}