diff --git a/code/lspgen/src/lspgen.c b/code/lspgen/src/lspgen.c index 7ba1518c..d05574d3 100644 --- a/code/lspgen/src/lspgen.c +++ b/code/lspgen/src/lspgen.c @@ -557,9 +557,9 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx) if (node->node_name) { lsdb_reset_attr_template(&attr_template); attr_template.key.ordinal = 1; - attr_template.key.msg[0] = OSPF_MSG_LSUPDATE; - attr_template.key.msg[1] = OSPF_LSA_OPAQUE_AREA; - attr_template.key.msg[2] = OSPF_TLV_HOSTNAME; + attr_template.key.attr_cp[0] = OSPF_MSG_LSUPDATE; + attr_template.key.attr_cp[1] = OSPF_LSA_OPAQUE_AREA_RI; + attr_template.key.attr_cp[2] = OSPF_TLV_HOSTNAME; strncpy(attr_template.key.hostname, node->node_name, sizeof(attr_template.key.hostname)-1); lsdb_add_node_attr(node, &attr_template); } @@ -576,9 +576,9 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx) } attr_template.key.prefix.node_flag = true; - attr_template.key.msg[0] = OSPF_MSG_LSUPDATE; - attr_template.key.msg[1] = OSPF_LSA_ROUTER; - attr_template.key.msg[2] = OSPF_ROUTER_LSA_LINK_STUB; + attr_template.key.attr_cp[0] = OSPF_MSG_LSUPDATE; + attr_template.key.attr_cp[1] = OSPF_LSA_ROUTER; + attr_template.key.attr_cp[2] = OSPF_ROUTER_LSA_LINK_STUB; lsdb_add_node_attr(node, &attr_template); /* external prefixes */ @@ -590,9 +590,8 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx) attr_template.key.prefix.ipv4_prefix.len = ctx->ipv4_ext_prefix.len; attr_template.key.prefix.metric = 100; - attr_template.key.msg[0] = OSPF_MSG_LSUPDATE; - attr_template.key.msg[1] = OSPF_LSA_EXTERNAL; - attr_template.key.msg[2] = OSPF_EXTERNAL_PREFIX;; + attr_template.key.attr_cp[0] = OSPF_MSG_LSUPDATE; + attr_template.key.attr_cp[1] = OSPF_LSA_EXTERNAL; lsdb_add_node_attr(node, &attr_template); ext_addr4 += ext_incr4; } @@ -625,9 +624,9 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx) * TODO Type-2 LSA handling. */ lsdb_reset_attr_template(&attr_template); - attr_template.key.msg[0] = OSPF_MSG_LSUPDATE; - attr_template.key.msg[1] = OSPF_LSA_ROUTER; - attr_template.key.msg[2] = OSPF_ROUTER_LSA_LINK_PTP; + attr_template.key.attr_cp[0] = OSPF_MSG_LSUPDATE; + attr_template.key.attr_cp[1] = OSPF_LSA_ROUTER; + attr_template.key.attr_cp[2] = 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); @@ -641,9 +640,9 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx) attr_template.key.prefix.ipv4_prefix.len = ctx->ipv4_link_prefix.len; attr_template.key.prefix.metric = link->link_metric; /* TODO clip metric */ - attr_template.key.msg[0] = OSPF_MSG_LSUPDATE; - attr_template.key.msg[1] = OSPF_LSA_ROUTER; - attr_template.key.msg[2] = OSPF_ROUTER_LSA_LINK_STUB; + attr_template.key.attr_cp[0] = OSPF_MSG_LSUPDATE; + attr_template.key.attr_cp[1] = OSPF_LSA_ROUTER; + attr_template.key.attr_cp[2] = 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 7e63c3c6..2732d602 100644 --- a/code/lspgen/src/lspgen.h +++ b/code/lspgen/src/lspgen.h @@ -58,6 +58,7 @@ extern struct keyval_ isis_level_names[]; /* lspgen_packet.c */ void lspgen_serialize_attr(lsdb_ctx_t *, lsdb_attr_t *, lsdb_packet_t *); void lspgen_gen_packet(lsdb_ctx_t *); +void lspgen_reset_packet_buffer(struct lsdb_packet_ *); /* lspgen_seq_cache.c */ void lspgen_read_seq_cache(lsdb_ctx_t *); diff --git a/code/lspgen/src/lspgen_lsdb.c b/code/lspgen/src/lspgen_lsdb.c index 54ac1ac9..e9fdbbab 100644 --- a/code/lspgen/src/lspgen_lsdb.c +++ b/code/lspgen/src/lspgen_lsdb.c @@ -748,8 +748,22 @@ lsdb_format_isis_attr(struct lsdb_attr_ *attr) return buf; } -struct keyval_ ospf_attr_names[] = { - { OSPF_TLV_HOSTNAME, "Hostname" }, +struct keyval_ ospf_attr_l0_names[] = { + { OSPF_MSG_LSUPDATE, "LS-Update" }, + { 0, NULL} +}; + +struct keyval_ ospf_attr_l1_names[] = { + { OSPF_LSA_ROUTER, "Router-LSA" }, + { OSPF_LSA_EXTERNAL, "External-LSA" }, + { OSPF_LSA_OPAQUE_AREA_RI, "Opaque-LSA-RI" }, + { 0, NULL} +}; + +struct keyval_ ospf_attr_l2_names[] = { + { OSPF_ROUTER_LSA_LINK_PTP, "ptp-link" }, + { OSPF_ROUTER_LSA_LINK_STUB, "ptp-stub" }, + { OSPF_TLV_HOSTNAME, "Hostname" }, { 0, NULL} }; @@ -758,16 +772,42 @@ lsdb_format_ospf2_attr(struct lsdb_attr_ *attr) { static char buf[128]; int len; + uint attr_cp; - 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; + attr_cp = attr->key.attr_cp[0]; + len = snprintf(buf, sizeof(buf), "%s", val2key(ospf_attr_l0_names, attr_cp)); + attr_cp = attr->key.attr_cp[1]; + if (attr_cp) { + len += snprintf(buf+len, sizeof(buf)-len, " %s", val2key(ospf_attr_l1_names, attr_cp)); } + attr_cp = attr->key.attr_cp[2]; + if (attr_cp) { + len += snprintf(buf+len, sizeof(buf)-len, " %s", val2key(ospf_attr_l2_names, attr_cp)); + } + + switch(attr->key.attr_cp[1]) { + case OSPF_LSA_EXTERNAL: + len += snprintf(buf+len, sizeof(buf)-len, " %s, metric %u", + format_ipv4_prefix(&attr->key.prefix.ipv4_prefix), + attr->key.prefix.metric); + break; + default: + break; + } + + switch(attr->key.attr_cp[2]) { + case OSPF_ROUTER_LSA_LINK_STUB: + len += snprintf(buf+len, sizeof(buf)-len, " %s, metric %u", + format_ipv4_prefix(&attr->key.prefix.ipv4_prefix), + attr->key.prefix.metric); + break; + case OSPF_TLV_HOSTNAME: + len += snprintf(buf+len, sizeof(buf)-len, ": %s", attr->key.hostname); + break; + default: + break; + } + return buf; } @@ -856,6 +896,7 @@ lsdb_add_node_attr(lsdb_node_t *node, lsdb_attr_t *attr_template) struct lsdb_attr_ *attr; void **p; lsdb_packet_t packet; + int idx; if (!node) { return NULL; @@ -911,20 +952,25 @@ lsdb_add_node_attr(lsdb_node_t *node, lsdb_attr_t *attr_template) /* * Calculate the size, by serializing the data into a dummy packet buffer. */ - packet.buf.data = packet.data; - //buf.data = data; - packet.buf.idx = 0; - //buf.idx = 0; - packet.buf.size = sizeof(packet.data); - //buf.size = sizeof(data); + lspgen_reset_packet_buffer(&packet); lspgen_serialize_attr(ctx, attr, &packet); attr->size = packet.buf.idx; - //attr->size = buf.idx; + + /* + * Find lowest level size. + */ + for (idx = MAX_MSG_LEVEL-1; idx; idx--) { + if (packet.bufX[idx].idx) { + attr->size += packet.bufX[idx].idx; + break; + } + } /* * Book keeping. */ node->attr_count++; + attr->parent = node; LOG(LSDB, " Add attr %s to node %s (%s), size %u\n", lsdb_format_attr(ctx, attr), diff --git a/code/lspgen/src/lspgen_lsdb.h b/code/lspgen/src/lspgen_lsdb.h index 26721d69..0ceb2e6a 100644 --- a/code/lspgen/src/lspgen_lsdb.h +++ b/code/lspgen/src/lspgen_lsdb.h @@ -262,6 +262,8 @@ typedef struct msg_stack_ { struct io_buffer_ buf[1]; /* variable length */ } msg_stack_t; +#define MAX_MSG_LEVEL 4 + /* * An Attribute hanging off a node or link */ @@ -272,7 +274,7 @@ typedef struct lsdb_attr_ { */ struct { uint8_t ordinal; /* Used for ordering message generation */ - uint8_t msg[4]; /* code points for multiple levels */ + uint8_t attr_cp[MAX_MSG_LEVEL]; /* code points for multiple levels */ uint8_t attr_type; /* Type */ bool start_tlv; /* Always start a fresh TLV */ union { @@ -289,6 +291,7 @@ typedef struct lsdb_attr_ { } key; uint32_t size; /* on-the wire space required in bytes */ + struct lsdb_node_ *parent; } lsdb_attr_t; /* @@ -309,10 +312,11 @@ typedef struct lsdb_packet_ { } key; struct io_buffer_ buf; + struct io_buffer_ bufX[MAX_MSG_LEVEL]; uint8_t data[1500]; /* fixed buffer */ uint8_t redzone[8]; /* Overwrite detection */ - uint8_t prev_attr_cp[4]; /* cached code points for previous attr */ + uint8_t prev_attr_cp[MAX_MSG_LEVEL]; /* cached code points for previous attr */ } lsdb_packet_t; diff --git a/code/lspgen/src/lspgen_ospf.h b/code/lspgen/src/lspgen_ospf.h index beebedd4..ebf2ec1d 100644 --- a/code/lspgen/src/lspgen_ospf.h +++ b/code/lspgen/src/lspgen_ospf.h @@ -17,7 +17,7 @@ #define OSPF_LSA_EXTERNAL 5 #define OSPF_LSA_OPAQUE_LINK 9 -#define OSPF_LSA_OPAQUE_AREA 10 +#define OSPF_LSA_OPAQUE_AREA_RI 104 #define OSPF_LSA_OPAQUE_DOMAIN 11 #define OSPF_TLV_HOSTNAME 7 @@ -26,7 +26,4 @@ enum { /* Router LSA */ OSPF_ROUTER_LSA_LINK_PTP, OSPF_ROUTER_LSA_LINK_STUB, - - /* External LSA */ - OSPF_EXTERNAL_PREFIX, }; diff --git a/code/lspgen/src/lspgen_packet.c b/code/lspgen/src/lspgen_packet.c index 3934259e..9dcd3c55 100644 --- a/code/lspgen/src/lspgen_packet.c +++ b/code/lspgen/src/lspgen_packet.c @@ -18,6 +18,8 @@ */ void lspgen_gen_packet_node(lsdb_node_t *); +#define PAD4(X) ((X+3)&(~3)) /* 32-Bit padding */ + void lspgen_gen_isis_packet_header(lsdb_ctx_t *ctx, lsdb_node_t *node, lsdb_packet_t *packet) { @@ -114,7 +116,7 @@ lspgen_gen_packet_header(lsdb_ctx_t *ctx, lsdb_node_t *node, lsdb_packet_t *pack lspgen_gen_isis_packet_header(ctx, node, packet); break; case PROTO_OSPF2: - lspgen_gen_ospf2_packet_header(ctx, node, packet); + //lspgen_gen_ospf2_packet_header(ctx, node, packet); break; default: LOG_NOARG(ERROR, "Unknown protocol\n"); @@ -597,26 +599,243 @@ lspgen_serialize_isis_attr(lsdb_attr_t *attr, lsdb_packet_t *packet) } } +/* + * Inititialize a next level buffer to the remnants of the passed in buffer. + * This gives us nice hierarchical buffers with vboundary protection. + */ +void +lspgen_propagate_buffer_down (lsdb_packet_t *packet, uint level) +{ + struct io_buffer_ *cur, *next; + + /* boundary protection */ + if (level >= MAX_MSG_LEVEL - 1) { + return; + } + + cur = &packet->bufX[level]; + next = &packet->bufX[level+1]; + + next->data = cur->data + cur->idx; + next->size = cur->size - cur->idx; + next->idx = 0; + next->start_idx = 0; +} + +void +lspgen_propagate_buffer_up (lsdb_packet_t *packet, uint level) +{ + struct io_buffer_ *cur, *prev; + + /* boundary protection */ + if (level == 0) { + return; + } + + cur = &packet->bufX[level]; + prev = &packet->bufX[level-1]; + + prev->idx += cur->idx; +} + /* * Serialize an OSPFv2 attribute into a packet buffer. */ void lspgen_serialize_ospf2_attr(lsdb_attr_t *attr, lsdb_packet_t *packet) { - io_buffer_t *buf; - uint16_t attr_len; + lsdb_node_t *node; + io_buffer_t *buf0, *buf1, *buf2; + uint16_t attr_len, checksum; + uint32_t router_id, mask; - buf = &packet->buf; + node = packet->parent; - 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; + buf0 = &packet->bufX[0]; + buf1 = &packet->bufX[1]; + buf2 = &packet->bufX[2]; + + /* + * New Level 0 message ? + */ + if (packet->prev_attr_cp[0] != attr->key.attr_cp[0]) { + + /* close Level 0 */ + switch (packet->prev_attr_cp[0]) { + case OSPF_MSG_LSUPDATE: + write_be_uint(buf0->data+2, 2, buf0->idx); /* Packet length */ + write_be_uint(buf0->data+12, 2, calculate_cksum(buf0->data, buf0->idx)); /* Checksum */ + break; + default: + break; + } + + /* open Level 0 */ + switch(attr->key.attr_cp[0]) { + case OSPF_MSG_LSUPDATE: + + push_be_uint(buf0, 1, 2); /* Version */ + push_be_uint(buf0, 1, OSPF_MSG_LSUPDATE); /* Msg */ + push_be_uint(buf0, 2, 0); /* Packet length - will be overwritten later */ + + router_id = read_be_uint(node->key.node_id, 4); + push_be_uint(buf0, 4, router_id); /* Router ID */ + push_be_uint(buf0, 4, node->ctx->topology_id.area); /* Area ID */ + + push_be_uint(buf0, 2, 0); /* Checksum - will be overwritten later */ + + push_be_uint(buf0, 2, 0); /* Authentication Type */ + push_be_uint(buf0, 8, 0); /* Authentication */ + + push_be_uint(buf0, 4, 0); /* # LSAs - will be overwritten later */ + + lspgen_propagate_buffer_down(packet, 0); + break; + default: + LOG(ERROR, "No Level 0 open packet serializer for attr %d\n", attr->key.attr_cp[0]); + return; + } + } + + /* + * New Level 1 message ? + */ + if (packet->prev_attr_cp[1] != attr->key.attr_cp[1]) { + + /* close Level 1 */ + switch (packet->prev_attr_cp[1]) { + case OSPF_LSA_ROUTER: + case OSPF_LSA_EXTERNAL: + case OSPF_LSA_OPAQUE_AREA_RI: + inc_be_uint(buf0->data+24, 4); /* Update #LSAs */ + + write_be_uint(buf1->data+16, 2, 0); /* reset checksum field */ + checksum = calculate_fletcher_cksum(buf1->data, 16, buf1->idx); + write_be_uint(packet->data+16, 2, checksum); /* LSA Checksum */ + + lspgen_propagate_buffer_up(packet, 1); + break; + } + + /* open Level 1 */ + switch(attr->key.attr_cp[1]) { + case OSPF_LSA_ROUTER: + push_be_uint(buf1, 2, 1); /* LS-age */ + push_be_uint(buf1, 1, 0); /* Options */ + push_be_uint(buf1, 1, OSPF_LSA_ROUTER); /* LS-Type */ + router_id = read_be_uint(node->key.node_id, 4); + push_be_uint(buf1, 4, router_id); /* Link State ID */ + push_be_uint(buf1, 4, router_id); /* Advertising Router */ + push_be_uint(&packet->buf, 4, node->sequence); /* Sequence */ + push_be_uint(buf1, 2, 0); /* Checksum - will be overwritten later */ + push_be_uint(buf1, 2, 0); /* Length - will be overwritten later */ + + push_be_uint(buf1, 1, 0x02); /* Flags, E */ + push_be_uint(buf1, 1, 0); + push_be_uint(buf1, 2, 0); /* # links - will be overwritten later */ + + lspgen_propagate_buffer_down(packet, 1); + break; + + case OSPF_LSA_EXTERNAL: + push_be_uint(buf1, 2, 1); /* LS-age */ + push_be_uint(buf1, 1, 0); /* Options */ + push_be_uint(buf1, 1, 5); /* LS-Type */ + push_data(buf1, (uint8_t*)&attr->key.prefix.ipv4_prefix.address, 4); /* Link State ID */ + router_id = read_be_uint(node->key.node_id, 4); + push_be_uint(buf1, 4, router_id); /* Advertising Router */ + push_be_uint(&packet->buf, 4, node->sequence); /* Sequence */ + push_be_uint(buf1, 2, 0); /* Checksum - will be overwritten later */ + push_be_uint(buf1, 2, 0); /* Length - will be overwritten later */ + + mask = 0xffffffff; + /* convert prefix length to mask */ + mask &= ~((1 << ((32 - attr->key.prefix.ipv4_prefix.len)))-1); + push_be_uint(buf1, 4, mask); /* Network Mask */ + + push_be_uint(buf1, 1, 0x80); /* E2 */ + push_be_uint(buf1, 1, 0); /* Options */ + push_be_uint(buf1, 3, attr->key.prefix.metric); /* Metric */ + push_be_uint(buf1, 4, 0); /* Forwarding Address */ + push_be_uint(buf1, 4, 0); /* External Route Tag */ + + lspgen_propagate_buffer_down(packet, 1); + break; + + case OSPF_LSA_OPAQUE_AREA_RI: + push_be_uint(buf1, 2, 1); /* LS-age */ + push_be_uint(buf1, 1, 0); /* Options */ + push_be_uint(buf1, 1, 10); /* LS-Type */ + push_be_uint(buf1, 1, 4); /* Opaque Type: Router-Information */ + push_be_uint(buf1, 3, 0); /* Opaque subtype */ + router_id = read_be_uint(node->key.node_id, 4); + push_be_uint(buf1, 4, router_id); /* Advertising Router */ + push_be_uint(&packet->buf, 4, node->sequence); /* Sequence */ + push_be_uint(buf1, 2, 0); /* Checksum - will be overwritten later */ + push_be_uint(buf1, 2, 0); /* Length - will be overwritten later */ + + lspgen_propagate_buffer_down(packet, 1); + break; + default: + LOG(ERROR, "No Level 1 open packet serializer for attr %d\n", attr->key.attr_cp[1]); + return; + } + } + + /* + * New Level 2 message ? + */ + if (packet->prev_attr_cp[2] != attr->key.attr_cp[2]) { + + /* close Level 2 */ + switch (packet->prev_attr_cp[2]) { + case OSPF_ROUTER_LSA_LINK_PTP: + case OSPF_ROUTER_LSA_LINK_STUB: + inc_be_uint(buf1->data+22, 1); /* Update #links */ + + lspgen_propagate_buffer_up(packet, 2); + break; + } + + /* open Level 2 */ + switch(attr->key.attr_cp[2]) { + case OSPF_ROUTER_LSA_LINK_PTP: + push_be_uint(buf2, 4, 0); /* Link ID */ + push_be_uint(buf2, 4, 0); /* Link Data */ + push_be_uint(buf2, 1, 1); /* Type ptp */ + push_be_uint(buf2, 1, 0); /* #TOS */ + push_be_uint(buf2, 2, 100); /* metric */ + + lspgen_propagate_buffer_down(packet, 2); + break; + + case OSPF_ROUTER_LSA_LINK_STUB: + push_be_uint(buf2, 4, 1); /* Link ID */ + push_be_uint(buf2, 4, 0xffffffff); /* Link Data */ + push_be_uint(buf2, 1, 3); /* Type stub */ + push_be_uint(buf2, 1, 0); /* #TOS */ + push_be_uint(buf2, 2, 100); /* metric */ + + lspgen_propagate_buffer_down(packet, 2); + break; + + case OSPF_TLV_HOSTNAME: + attr_len = strnlen(attr->key.hostname, sizeof(attr->key.hostname)); + if (attr_len) { + push_be_uint(buf2, 2, 7); /* Type */ + push_be_uint(buf2, 2, attr_len); /* Length */ + push_data(buf2, (uint8_t *)attr->key.hostname, attr_len); + push_be_uint(buf2, PAD4(attr_len), 0); /* Padding zeros */ + } + + lspgen_propagate_buffer_down(packet, 2); + break; + + default: + LOG(ERROR, "No Level 2 open packet serializer for attr %d\n", attr->key.attr_cp[2]); + return; + } - default: - LOG(ERROR, "No packet serializer for attr %d\n", attr->key.attr_type); - break; } } @@ -666,6 +885,23 @@ lspgen_calculate_tlv_space(io_buffer_t *buf, uint32_t tlv_start_idx) return 255 - tlv_len; } +/* + * Reset all packet buffers. + */ +void +lspgen_reset_packet_buffer (struct lsdb_packet_ *packet) +{ + uint idx; + + packet->buf.data = packet->data; + packet->buf.start_idx = 0; + packet->buf.idx = 0; + packet->buf.size = sizeof(packet->data); + for (idx = 0; idx < MAX_MSG_LEVEL; idx++) { + memcpy(&packet->bufX[idx], &packet->buf, sizeof(struct io_buffer_)); + } +} + /* * Lookup / Create a fresh packet based on the id. */ @@ -711,6 +947,11 @@ lspgen_add_packet(lsdb_ctx_t *ctx, lsdb_node_t *node, uint32_t id) */ packet->parent = node; + /* + * Reset buffers. + */ + lspgen_reset_packet_buffer(packet); + /* * Write header for link-state packet. */