start work on OSPF serializer

This commit is contained in:
Hannes Gredler
2023-07-27 15:03:18 +00:00
committed by Christian Giese
parent 4917f751dd
commit 09afad7320
4 changed files with 274 additions and 43 deletions
+16 -10
View File
@@ -12,6 +12,7 @@
#include "lspgen.h"
#include "lspgen_lsdb.h"
#include "lspgen_isis.h"
#include "lspgen_ospf.h"
/*
* Globals
@@ -555,8 +556,8 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx)
/* Host name */
if (node->node_name) {
lsdb_reset_attr_template(&attr_template);
attr_template.key.ordinal = 1;
attr_template.key.attr_type = ISIS_TLV_HOSTNAME;
attr_template.key.ordinal = OSPF_LSA_OPAQUE_AREA;
attr_template.key.attr_type = OSPF_TLV_HOSTNAME;
strncpy(attr_template.key.hostname, node->node_name, sizeof(attr_template.key.hostname)-1);
lsdb_add_node_attr(node, &attr_template);
}
@@ -572,8 +573,8 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx)
attr_template.key.prefix.adv_sid = true;
}
attr_template.key.prefix.node_flag = true;
attr_template.key.ordinal = 1;
attr_template.key.attr_type = ISIS_TLV_EXTD_IPV4_REACH;
attr_template.key.ordinal = OSPF_LSA_ROUTER;
attr_template.key.attr_type = OSPF_ROUTER_LSA_LINK_STUB;
lsdb_add_node_attr(node, &attr_template);
/* external prefixes */
@@ -584,11 +585,13 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx)
lspgen_store_addr(ext_addr4, (uint8_t*)&attr_template.key.prefix.ipv4_prefix.address, 4);
attr_template.key.prefix.ipv4_prefix.len = ctx->ipv4_ext_prefix.len;
attr_template.key.prefix.metric = 100;
attr_template.key.attr_type = ISIS_TLV_EXTD_IPV4_REACH;
attr_template.key.ordinal = OSPF_LSA_EXTERNAL;
attr_template.key.attr_type = OSPF_EXTERNAL_PREFIX;
lsdb_add_node_attr(node, &attr_template);
ext_addr4 += ext_incr4;
}
#if 0
if (!ctx->no_sr) {
/* SR capability */
lsdb_reset_attr_template(&attr_template);
@@ -604,6 +607,7 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx)
attr_template.key.ordinal = 1;
lsdb_add_node_attr(node, &attr_template);
}
#endif
/*
* Walk all of our neighbors.
@@ -612,9 +616,10 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx)
/* Generate an IS reach for each link */
lsdb_reset_attr_template(&attr_template);
attr_template.key.attr_type = ISIS_TLV_EXTD_IS_REACH;
memcpy(attr_template.key.link.remote_node_id, link->key.remote_node_id, 7);
attr_template.key.link.metric = link->link_metric;
attr_template.key.ordinal = OSPF_LSA_ROUTER;
attr_template.key.attr_type = OSPF_ROUTER_LSA_LINK_PTP;
memcpy(attr_template.key.link.remote_node_id, link->key.remote_node_id, 4);
attr_template.key.link.metric = link->link_metric; /* TODO clip metric */
lsdb_add_node_attr(node, &attr_template);
/* Generate an IPv4 prefix for each link */
@@ -624,8 +629,9 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx)
addr += link->link_index * inc;
lspgen_store_addr(addr, (uint8_t*)&attr_template.key.prefix.ipv4_prefix.address, sizeof(ipv4addr_t));
attr_template.key.prefix.ipv4_prefix.len = ctx->ipv4_link_prefix.len;
attr_template.key.prefix.metric = link->link_metric;
attr_template.key.attr_type = ISIS_TLV_EXTD_IPV4_REACH;
attr_template.key.prefix.metric = link->link_metric; /* TODO clip metric */
attr_template.key.ordinal = OSPF_LSA_ROUTER;
attr_template.key.attr_type = OSPF_ROUTER_LSA_LINK_STUB;
lsdb_add_node_attr(node, &attr_template);
}
+1 -1
View File
@@ -56,7 +56,7 @@ void lspgen_write_config(lsdb_ctx_t *);
extern struct keyval_ isis_level_names[];
/* lspgen_packet.c */
void lspgen_serialize_attr(lsdb_attr_t *, io_buffer_t *);
void lspgen_serialize_attr(lsdb_ctx_t *, lsdb_attr_t *, io_buffer_t *);
void lspgen_gen_packet(lsdb_ctx_t *);
/* lspgen_seq_cache.c */
+63 -11
View File
@@ -12,6 +12,7 @@
#include "lspgen.h"
#include "lspgen_lsdb.h"
#include "lspgen_isis.h"
#include "lspgen_ospf.h"
/*
* Convert the node_id string to binary data.
@@ -690,7 +691,7 @@ lsdb_get_link(struct lsdb_ctx_ *ctx, struct lsdb_link_ *link_template)
/*
* Link State Attributes / name mappings
*/
struct keyval_ attr_names[] = {
struct keyval_ isis_attr_names[] = {
{ ISIS_TLV_AREA, "Area" },
{ ISIS_TLV_PROTOCOLS, "Protocol" },
{ ISIS_TLV_EXTD_IS_REACH, "Link" },
@@ -704,12 +705,12 @@ struct keyval_ attr_names[] = {
};
char *
lsdb_format_attr(struct lsdb_attr_ *attr)
lsdb_format_isis_attr(struct lsdb_attr_ *attr)
{
static char buf[128];
int len;
len = snprintf(buf, sizeof(buf), "%s (%u)", val2key(attr_names, attr->key.attr_type), attr->key.attr_type);
len = snprintf(buf, sizeof(buf), "%s (%u)", val2key(isis_attr_names, attr->key.attr_type), attr->key.attr_type);
switch(attr->key.attr_type) {
case ISIS_TLV_PROTOCOLS:
@@ -747,6 +748,43 @@ lsdb_format_attr(struct lsdb_attr_ *attr)
return buf;
}
struct keyval_ ospf_attr_names[] = {
{ OSPF_TLV_HOSTNAME, "Hostname" },
{ 0, NULL}
};
char *
lsdb_format_ospf2_attr(struct lsdb_attr_ *attr)
{
static char buf[128];
int len;
len = snprintf(buf, sizeof(buf), "%s (%u)", val2key(ospf_attr_names, attr->key.attr_type), attr->key.attr_type);
switch(attr->key.attr_type) {
case OSPF_TLV_HOSTNAME:
len += snprintf(buf+len, sizeof(buf)-len, " '%s'", attr->key.hostname);
break;
default:
break;
}
return buf;
}
char *
lsdb_format_attr(lsdb_ctx_t *ctx, struct lsdb_attr_ *attr)
{
switch (ctx->protocol_id) {
case PROTO_ISIS:
return lsdb_format_isis_attr(attr);
case PROTO_OSPF2:
return lsdb_format_ospf2_attr(attr);
default:
LOG_NOARG(ERROR, "Unknown protocol\n");
}
return "Unknown protocol";
}
/*
* Use this function to clear attributes.
* The default ordinal is set to the worst.
@@ -760,9 +798,10 @@ lsdb_reset_attr_template(lsdb_attr_t *attr_template)
}
bool
lsdb_is_ipv4_attr(lsdb_attr_t *attr)
lsdb_is_ipv4_attr(lsdb_ctx_t *ctx, lsdb_attr_t *attr)
{
switch (attr->key.attr_type) {
if (ctx->protocol_id == PROTO_ISIS) {
switch (attr->key.attr_type) {
case ISIS_TLV_IPV4_ADDR:
case ISIS_TLV_EXTD_IPV4_REACH:
return true;
@@ -773,14 +812,20 @@ lsdb_is_ipv4_attr(lsdb_attr_t *attr)
break;
default:
break;
}
} else if (ctx->protocol_id == PROTO_OSPF2) {
/* OSPFv2 only has IPV4 related attributes added */
return true;
}
return false;
}
bool
lsdb_is_ipv6_attr(lsdb_attr_t *attr)
lsdb_is_ipv6_attr(lsdb_ctx_t *ctx, lsdb_attr_t *attr)
{
switch (attr->key.attr_type) {
if (ctx->protocol_id == PROTO_ISIS) {
switch (attr->key.attr_type) {
case ISIS_TLV_IPV6_ADDR:
case ISIS_TLV_EXTD_IPV6_REACH:
return true;
@@ -791,6 +836,10 @@ lsdb_is_ipv6_attr(lsdb_attr_t *attr)
break;
default:
break;
}
} else if (ctx->protocol_id == PROTO_OSPF3) {
/* OSPFv3 only has IPV6 related attributes added */
return true;
}
return false;
}
@@ -803,6 +852,7 @@ lsdb_attr_t *
lsdb_add_node_attr(lsdb_node_t *node, lsdb_attr_t *attr_template)
{
dict_insert_result result;
lsdb_ctx_t *ctx;
struct lsdb_attr_ *attr;
void **p;
uint8_t data[255]; /* One max-sized TLV */
@@ -812,17 +862,19 @@ lsdb_add_node_attr(lsdb_node_t *node, lsdb_attr_t *attr_template)
return NULL;
}
ctx = node->ctx;
/*
* Refuse addition of v4 attributes if v4 is turned off.
*/
if (node->ctx->no_ipv4 && lsdb_is_ipv4_attr(attr_template)) {
if (ctx->no_ipv4 && lsdb_is_ipv4_attr(ctx, attr_template)) {
return NULL;
}
/*
* Refuse addition of v6 attributes if v6 is turned off.
*/
if (node->ctx->no_ipv6 && lsdb_is_ipv6_attr(attr_template)) {
if (ctx->no_ipv6 && lsdb_is_ipv6_attr(ctx, attr_template)) {
return NULL;
}
@@ -863,7 +915,7 @@ lsdb_add_node_attr(lsdb_node_t *node, lsdb_attr_t *attr_template)
buf.data = data;
buf.idx = 0;
buf.size = sizeof(data);
lspgen_serialize_attr(attr, &buf);
lspgen_serialize_attr(ctx, attr, &buf);
attr->size = buf.idx;
/*
@@ -872,7 +924,7 @@ lsdb_add_node_attr(lsdb_node_t *node, lsdb_attr_t *attr_template)
node->attr_count++;
LOG(LSDB, " Add attr %s to node %s (%s), size %u\n",
lsdb_format_attr(attr),
lsdb_format_attr(ctx, attr),
lsdb_format_node(node),
lsdb_format_node_id(node->key.node_id),
attr->size);
+194 -21
View File
@@ -10,6 +10,7 @@
#include "lspgen.h"
#include "lspgen_lsdb.h"
#include "lspgen_isis.h"
#include "lspgen_ospf.h"
#include "hmac_md5.h"
/*
@@ -205,7 +206,7 @@ calculate_cksum(uint8_t *buf, uint16_t len)
* Helper for calculating when to start a new packet.
*/
uint32_t
lspgen_calculate_auth_len(lsdb_ctx_t *ctx)
lspgen_calculate_isis_auth_len(lsdb_ctx_t *ctx)
{
uint8_t auth_len;
@@ -429,14 +430,10 @@ lspgen_serialize_prefix_subtlv(lsdb_attr_t *attr, io_buffer_t *buf,
}
/*
* Serialize a attribute into a buffer.
*
* This is used in two places.
* 1) When an attribute gets added for size measurement.
* 2) When the actual link-state packets gets built.
* Serialize an IS-IS attribute into a buffer.
*/
void
lspgen_serialize_attr(lsdb_attr_t *attr, io_buffer_t *buf)
lspgen_serialize_isis_attr(lsdb_attr_t *attr, io_buffer_t *buf)
{
uint32_t metric, mask;
uint8_t attr_len, flags;
@@ -597,6 +594,48 @@ lspgen_serialize_attr(lsdb_attr_t *attr, io_buffer_t *buf)
}
}
/*
* Serialize an OSPFv2 attribute into a buffer.
*/
void
lspgen_serialize_ospf2_attr(lsdb_attr_t *attr, io_buffer_t *buf)
{
uint16_t attr_len;
switch (attr->key.attr_type) {
case OSPF_TLV_HOSTNAME:
attr_len = strnlen(attr->key.hostname, sizeof(attr->key.hostname));
push_data(buf, (uint8_t *)attr->key.hostname, attr_len);
break;
default:
LOG(ERROR, "No packet serializer for attr %d\n", attr->key.attr_type);
break;
}
}
/*
* Serialize a attribute into a buffer.
*
* This is used in two places.
* 1) When an attribute gets added for size measurement.
* 2) When the actual link-state packets gets built.
*/
void
lspgen_serialize_attr(lsdb_ctx_t *ctx, lsdb_attr_t *attr, io_buffer_t *buf)
{
switch (ctx->protocol_id) {
case PROTO_ISIS:
lspgen_serialize_isis_attr(attr, buf);
break;
case PROTO_OSPF2:
lspgen_serialize_ospf2_attr(attr, buf);
break;
default:
LOG_NOARG(ERROR, "Unknown protocol\n");
}
}
/*
* Update length field of last TLV written to the buffer.
*/
@@ -722,10 +761,10 @@ lspgen_refresh_interval (lsdb_ctx_t *ctx)
}
/*
* Walk the graph of the LSDB and serialize packets.
* Walk the graph of the LSDB and serialize IS-IS packets.
*/
void
lspgen_gen_packet_node(lsdb_node_t *node)
lspgen_gen_isis_packet_node(lsdb_node_t *node)
{
lsdb_ctx_t *ctx;
struct lsdb_packet_ *packet;
@@ -785,7 +824,7 @@ lspgen_gen_packet_node(lsdb_node_t *node)
/*
* Space left in this packet ?
*/
min_len = lspgen_calculate_auth_len(ctx);
min_len = lspgen_calculate_isis_auth_len(ctx);
min_len += attr->size + TLV_OVERHEAD;
if (packet && packet->buf.idx > (1465-min_len)) {
@@ -826,7 +865,7 @@ lspgen_gen_packet_node(lsdb_node_t *node)
push_be_uint(&packet->buf, 1, 0); /* Length */
}
lspgen_serialize_attr(attr, &packet->buf);
lspgen_serialize_attr(ctx, attr, &packet->buf);
lspgen_update_tlv_length(&packet->buf, tlv_start_idx);
last_attr = attr->key.attr_type;
@@ -837,6 +876,140 @@ lspgen_gen_packet_node(lsdb_node_t *node)
dict_itor_free(itor);
}
/*
* Walk the graph of the LSDB and serialize OSPFv2 packets.
*/
void
lspgen_gen_ospf2_packet_node(lsdb_node_t *node)
{
lsdb_ctx_t *ctx;
struct lsdb_packet_ *packet;
struct lsdb_attr_ *attr;
dict_itor *itor;
uint32_t id, last_attr, tlv_start_idx, min_len;
ctx = node->ctx;
packet = NULL;
id = 0;
last_attr = 0;
tlv_start_idx = 0;
/*
* Flush old serialized packets.
*/
dict_clear(node->packet_dict, lsdb_free_packet);
if (!node->attr_dict) {
/*
* No attributes. This is a purge.
*/
packet = lspgen_add_packet(ctx, node, id);
lspgen_finalize_packet(ctx, node, packet);
return;
}
/*
* Walk the node attributes.
*/
itor = dict_itor_new(node->attr_dict);
if (!itor) {
return;
}
/*
* Node DB empty ?
*/
if (!dict_itor_first(itor)) {
dict_itor_free(itor);
LOG(ERROR, "No Attributes for node %s\n", lsdb_format_node(node));
return;
}
/*
* Start refresh timer.
*/
if (ctx->ctrl_socket_path) {
timer_add_periodic(&ctx->timer_root, &node->refresh_timer, "refresh",
lspgen_refresh_interval(ctx), 0, node, &lspgen_refresh_cb);
}
do {
attr = *dict_itor_datum(itor);
/*
* Space left in this packet ?
*/
min_len = lspgen_calculate_isis_auth_len(ctx);
min_len += attr->size + TLV_OVERHEAD;
if (packet && packet->buf.idx > (1465-min_len)) {
/*
* No space left. Finalize this packet.
*/
lspgen_finalize_packet(ctx, node, packet);
packet = NULL;
id++;
if (id > 255) {
dict_itor_free(itor);
LOG(ERROR, "Exhausted fragments for node %s\n", lsdb_format_node(node));
return;
}
}
/*
* Need a fresh packet ?
*/
if (!packet) {
packet = lspgen_add_packet(ctx, node, id);
tlv_start_idx = packet->buf.idx;
}
/*
* Encode node attributes.
*/
/*
* Start a fresh TLV ?
*/
if ((last_attr != attr->key.attr_type) ||
(lspgen_calculate_tlv_space(&packet->buf, tlv_start_idx) < attr->size) ||
attr->key.start_tlv) {
tlv_start_idx = packet->buf.idx;
push_be_uint(&packet->buf, 1, attr->key.attr_type); /* Type */
push_be_uint(&packet->buf, 1, 0); /* Length */
}
lspgen_serialize_attr(ctx, attr, &packet->buf);
lspgen_update_tlv_length(&packet->buf, tlv_start_idx);
last_attr = attr->key.attr_type;
} while (dict_itor_next(itor));
lspgen_finalize_packet(ctx, node, packet);
dict_itor_free(itor);
}
void
lspgen_gen_packet_node(lsdb_node_t *node)
{
lsdb_ctx_t *ctx;
ctx = node->ctx;
switch (ctx->protocol_id) {
case PROTO_ISIS:
lspgen_gen_isis_packet_node(node);
break;
case PROTO_OSPF2:
lspgen_gen_ospf2_packet_node(node);
break;
default:
LOG_NOARG(ERROR, "Unknown protocol\n");
}
}
/*
* Walk the graph of the LSDB and serialize packets.
*/
@@ -866,17 +1039,17 @@ lspgen_gen_packet(lsdb_ctx_t *ctx)
do {
node = *dict_itor_datum(itor);
/*
* Init per-packet tree for this node.
*/
if (!node->packet_dict) {
node->packet_dict = hb_dict_new((dict_compare_func)lsdb_compare_packet);
}
/*
* Init per-packet tree for this node.
*/
if (!node->packet_dict) {
node->packet_dict = hb_dict_new((dict_compare_func)lsdb_compare_packet);
}
/*
* Generate the link-state packets for this node.
*/
lspgen_gen_packet_node(node);
/*
* Generate the link-state packets for this node.
*/
lspgen_gen_packet_node(node);
} while (dict_itor_next(itor));