From 09afad7320bf84af23eab8de2f3cd98ab84eefef Mon Sep 17 00:00:00 2001 From: Hannes Gredler Date: Thu, 27 Jul 2023 15:03:18 +0000 Subject: [PATCH] start work on OSPF serializer --- code/lspgen/src/lspgen.c | 26 ++-- code/lspgen/src/lspgen.h | 2 +- code/lspgen/src/lspgen_lsdb.c | 74 +++++++++-- code/lspgen/src/lspgen_packet.c | 215 ++++++++++++++++++++++++++++---- 4 files changed, 274 insertions(+), 43 deletions(-) diff --git a/code/lspgen/src/lspgen.c b/code/lspgen/src/lspgen.c index 8cfead28..ca830921 100644 --- a/code/lspgen/src/lspgen.c +++ b/code/lspgen/src/lspgen.c @@ -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); } diff --git a/code/lspgen/src/lspgen.h b/code/lspgen/src/lspgen.h index af6c2ce8..90f831ed 100644 --- a/code/lspgen/src/lspgen.h +++ b/code/lspgen/src/lspgen.h @@ -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 */ diff --git a/code/lspgen/src/lspgen_lsdb.c b/code/lspgen/src/lspgen_lsdb.c index c1e927b1..5e4631a7 100644 --- a/code/lspgen/src/lspgen_lsdb.c +++ b/code/lspgen/src/lspgen_lsdb.c @@ -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); diff --git a/code/lspgen/src/lspgen_packet.c b/code/lspgen/src/lspgen_packet.c index 3e9b962c..dd022f9e 100644 --- a/code/lspgen/src/lspgen_packet.c +++ b/code/lspgen/src/lspgen_packet.c @@ -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));