diff --git a/code/lspgen/src/lspgen.c b/code/lspgen/src/lspgen.c index cdb7a948..0a73442b 100644 --- a/code/lspgen/src/lspgen.c +++ b/code/lspgen/src/lspgen.c @@ -97,7 +97,7 @@ struct keyval_ log_names[] = { struct keyval_ proto_names[] = { { PROTO_ISIS, "isis" }, { PROTO_OSPF2, "ospf2" }, - //{ PROTO_OSPF3, "ospf3" }, + { PROTO_OSPF3, "ospf3" }, { 0, NULL} }; @@ -466,7 +466,7 @@ lspgen_gen_isis_attr(struct lsdb_ctx_ *ctx) /* ipv6 external prefix */ lsdb_reset_attr_template(&attr_template); - lspgen_store_addr(ext_addr6, attr_template.key.prefix.ipv6_prefix.address, 16); + lspgen_store_addr(ext_addr6, attr_template.key.prefix.ipv6_prefix.address, IPV6_ADDR_LEN); attr_template.key.prefix.ipv6_prefix.len = ctx->ipv6_ext_prefix.len; attr_template.key.prefix.metric = 100; attr_template.key.attr_type = ISIS_TLV_EXTD_IPV6_REACH; @@ -607,7 +607,8 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx) attr_template.key.ordinal = 1; attr_template.key.attr_cp[0] = OSPF_MSG_LSUPDATE; attr_template.key.attr_cp[1] = OSPF_LSA_OPAQUE_AREA_EP; - attr_template.key.attr_cp[2] = OSPF_TLV_EXTENDED_PREFIX_RANGE; + attr_template.key.attr_cp[2] = OSPF_TLV_EXTENDED_PREFIX; + attr_template.key.attr_cp[3] = OSPF_SUBTLV_EXTENDED_PREFIX_SID;; lsdb_add_node_attr(node, &attr_template); } addr += node->node_index; @@ -650,7 +651,7 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx) CIRCLEQ_FOREACH(link, &node->link_qhead, link_qnode) { /* - * Is this a conncetor link ? + * Is this a connector link ? */ if (link->key.remote_node_id[7] == CONNECTOR_MARKER) { lsdb_reset_attr_template(&attr_template); @@ -711,6 +712,185 @@ lspgen_gen_ospf2_attr(struct lsdb_ctx_ *ctx) dict_itor_free(itor); } +/* + * Walk the graph of the LSDB and add the required node/link attributes for OSPFv3 LSP generation. + */ +void +lspgen_gen_ospf3_attr(struct lsdb_ctx_ *ctx) +{ + struct lsdb_node_ *node; + struct lsdb_link_ *link; + struct lsdb_attr_ attr_template; + dict_itor *itor; + __uint128_t addr, inc, ext_addr6, ext_incr6, addr_offset; + uint32_t ext_per_node, metric, nodes_left, ext_left; + + /* + * Walk the node DB. + */ + itor = dict_itor_new(ctx->node_dict); + if (!itor) { + return; + } + + /* + * Node DB empty ? + */ + if (!dict_itor_first(itor)) { + dict_itor_free(itor); + LOG_NOARG(ERROR, "Empty LSDB.\n"); + return; + } + + /* + * For external routes load the first address of the pool. + */ + ext_addr6 = lspgen_load_addr((uint8_t*)&ctx->ipv6_ext_prefix.address, IPV6_ADDR_LEN); + ext_incr6 = lspgen_get_prefix_inc(AF_INET6, ctx->ipv6_ext_prefix.len); + + nodes_left = ctx->num_nodes; + ext_left = ctx->num_ext; + + do { + node = *dict_itor_datum(itor); + + /* Host name */ + if (node->node_name) { + lsdb_reset_attr_template(&attr_template); + //attr_template.key.ordinal = 1; + 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); + } + + /* IPv6 loopback prefix */ + lsdb_reset_attr_template(&attr_template); + addr = lspgen_load_addr((uint8_t*)&ctx->ipv6_node_prefix.address, IPV6_ADDR_LEN); + lspgen_store_addr(addr, attr_template.key.prefix.ipv6_prefix.address, IPV6_ADDR_LEN); + attr_template.key.prefix.ipv6_prefix.len = ctx->ipv6_node_prefix.len; + attr_template.key.attr_cp[0] = OSPF_MSG_LSUPDATE; + attr_template.key.attr_cp[1] = OSPF_LSA_INTRA_AREA_PREFIX; + attr_template.key.attr_cp[2] = OSPF_IA_PREFIX_LSA_PREFIX; + lsdb_add_node_attr(node, &attr_template); + +#if 0 + if (!ctx->no_sr) { + lsdb_reset_attr_template(&attr_template); + lspgen_store_addr(addr, (uint8_t*)&attr_template.key.prefix.ipv6_prefix.address, IPV6_ADDR_LEN); + attr_template.key.prefix.ipv6_prefix.len = ctx->ipv6_node_prefix.len; + attr_template.key.prefix.sid = node->node_index; + + attr_template.key.ordinal = 1; + attr_template.key.attr_cp[0] = OSPF_MSG_LSUPDATE; + attr_template.key.attr_cp[1] = OSPF_LSA_OPAQUE_AREA_EP; + attr_template.key.attr_cp[2] = OSPF_TLV_EXTENDED_PREFIX_RANGE; + lsdb_add_node_attr(node, &attr_template); + } + addr += node->node_index; +#endif + + /* external prefixes */ + ext_per_node = ext_left / nodes_left; + ext_left -= ext_per_node; + while (ext_per_node--) { + /* ipv6 external prefix */ + lsdb_reset_attr_template(&attr_template); + lspgen_store_addr(ext_addr6, attr_template.key.prefix.ipv6_prefix.address, IPV6_ADDR_LEN); + attr_template.key.prefix.ipv6_prefix.len = ctx->ipv6_ext_prefix.len; + attr_template.key.prefix.metric = 100; + attr_template.key.attr_cp[0] = OSPF_MSG_LSUPDATE; + attr_template.key.attr_cp[1] = OSPF_LSA_EXTERNAL; + attr_template.key.start_tlv = true; + lsdb_add_node_attr(node, &attr_template); + ext_addr6 += ext_incr6; + } + + if (!ctx->no_sr) { + /* SR capability */ + lsdb_reset_attr_template(&attr_template); + addr = lspgen_load_addr((uint8_t*)&ctx->ipv4_node_prefix.address, sizeof(ipv4addr_t)); + addr += node->node_index; + lspgen_store_addr(addr, attr_template.key.cap.router_id, sizeof(ipv4addr_t)); + attr_template.key.cap.srgb_base = ctx->srgb_base; + attr_template.key.cap.srgb_range = ctx->srgb_range; + 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_SID_LABEL_RANGE; + //attr_template.key.ordinal = 1; + lsdb_add_node_attr(node, &attr_template); + } + + /* + * Walk all of our neighbors. + */ + CIRCLEQ_FOREACH(link, &node->link_qhead, link_qnode) { + + /* + * Is this a connector link ? + */ + if (link->key.remote_node_id[7] == CONNECTOR_MARKER) { + lsdb_reset_attr_template(&attr_template); + + 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); + memcpy(attr_template.key.link.local_node_id, link->key.local_link_id, 4); + attr_template.key.link.metric = link->link_metric; + lsdb_add_node_attr(node, &attr_template); + continue; + } + + /* + * Generate a ptp neighbor for each link + * TODO Type-2 LSA handling. + */ + lsdb_reset_attr_template(&attr_template); + + addr = lspgen_load_addr((uint8_t*)&ctx->ipv4_link_prefix.address, sizeof(ipv4addr_t)); + inc = lspgen_get_prefix_inc(AF_INET, ctx->ipv4_link_prefix.len); + addr += link->link_index * inc; + addr_offset = 0; + if (lspgen_load_addr(link->key.remote_node_id, 4) < lspgen_load_addr(link->key.local_node_id, 4)) { + addr_offset = 1; + } + + lspgen_store_addr(addr + addr_offset, attr_template.key.link.local_node_id, 4); + + 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); + metric = link->link_metric; + if (metric > 65535) { + metric = 65535; + } + attr_template.key.link.metric = metric; + lsdb_add_node_attr(node, &attr_template); + +#if 0 + /* Generate an IPv6 prefix for each link */ + lsdb_reset_attr_template(&attr_template); + lspgen_store_addr(addr, (uint8_t*)&attr_template.key.prefix.ipv6_prefix.address, IPV6_ADDR_LEN); + attr_template.key.prefix.ipv6_prefix.len = ctx->ipv6_link_prefix.len; + attr_template.key.prefix.metric = metric; + + attr_template.key.attr_cp[0] = OSPF_MSG_LSUPDATE; + attr_template.key.attr_cp[1] = OSPF_LSA_INTRA_AREA_PREFIX; + attr_template.key.attr_cp[2] = OSPF_IA_PREFIX_LSA_PREFIX; + lsdb_add_node_attr(node, &attr_template); +#endif + } + + nodes_left--; + } while (dict_itor_next(itor)); + + dict_itor_free(itor); +} + void lspgen_init_ctx(struct lsdb_ctx_ *ctx) { @@ -798,9 +978,9 @@ lspgen_compute_end_prefix6(struct ipv6_prefix_ *start_prefix, unsigned int num_p } prefix_inc = lspgen_get_prefix_inc(AF_INET6, start_prefix->len); - addr = lspgen_load_addr((uint8_t *)&start_prefix->address, 16); + addr = lspgen_load_addr((uint8_t *)&start_prefix->address, IPV6_ADDR_LEN); addr += prefix_inc * (num_prefixes-1); - lspgen_store_addr(addr, (uint8_t *)&end_prefix.address, 16); + lspgen_store_addr(addr, (uint8_t *)&end_prefix.address, IPV6_ADDR_LEN); return &end_prefix; } @@ -1243,8 +1423,9 @@ main(int argc, char *argv[]) lspgen_gen_isis_attr(ctx); } else if (ctx->protocol_id == PROTO_OSPF2) { lspgen_gen_ospf2_attr(ctx); + } else if (ctx->protocol_id == PROTO_OSPF3) { + lspgen_gen_ospf3_attr(ctx); } - } /* diff --git a/code/lspgen/src/lspgen_ctrl.c b/code/lspgen/src/lspgen_ctrl.c index f3daf6eb..bba5c1f0 100644 --- a/code/lspgen/src/lspgen_ctrl.c +++ b/code/lspgen/src/lspgen_ctrl.c @@ -161,7 +161,7 @@ lspgen_write_ctrl_buffer(lsdb_ctx_t *ctx) static void lspgen_ctrl_encode_packet(lsdb_ctx_t *ctx, lsdb_packet_t *packet) { - struct io_buffer_ *buf; + struct io_buffer_ *buf, *src_buf; char hextable[] = "0123456789abcdef"; uint8_t hi_byte, lo_byte; uint32_t idx, val; @@ -185,9 +185,10 @@ lspgen_ctrl_encode_packet(lsdb_ctx_t *ctx, lsdb_packet_t *packet) idx = 20; } - for (; idx < packet->buf.idx; idx++) { - hi_byte = packet->buf.data[idx] >> 4; - lo_byte = packet->buf.data[idx] & 0xf; + src_buf = &packet->buf[0]; + for (; idx < src_buf->idx; idx++) { + hi_byte = src_buf->data[idx] >> 4; + lo_byte = src_buf->data[idx] & 0xf; val = (hextable[hi_byte] << 8) | hextable[lo_byte]; push_be_uint(buf, 2, val); @@ -285,7 +286,7 @@ lspgen_ctrl_write_cb(timer_s *timer) /* * Hexdumping doubles the data plus 4 bytes for two quotation marks, comma and whitespace. */ - if (buffer_left < ((packet->buf.idx * 2) + 4)) { + if (buffer_left < ((packet->buf[0].idx * 2) + 4)) { /* no space, release buffer and try later */ lspgen_write_ctrl_buffer(ctx); diff --git a/code/lspgen/src/lspgen_lsdb.c b/code/lspgen/src/lspgen_lsdb.c index 9d24d15d..493334ef 100644 --- a/code/lspgen/src/lspgen_lsdb.c +++ b/code/lspgen/src/lspgen_lsdb.c @@ -181,10 +181,10 @@ lsdb_format_node(lsdb_node_t *node) if (ctx->protocol_id == PROTO_ISIS) { if (node->node_name) { - snprintf(buffer, sizeof(buffer), "%s (%s)", + snprintf(buffer, sizeof(buffer), "%s (%s)", lsdb_format_node_id(node->key.node_id), node->node_name); } else { - snprintf(buffer, sizeof(buffer), "%s", + snprintf(buffer, sizeof(buffer), "%s", lsdb_format_node_id(node->key.node_id)); } } else if (ctx->protocol_id == PROTO_OSPF2 || ctx->protocol_id == PROTO_OSPF3) { @@ -962,14 +962,14 @@ lsdb_add_node_attr(lsdb_node_t *node, lsdb_attr_t *attr_template) */ lspgen_reset_packet_buffer(&packet); lspgen_serialize_attr(ctx, attr, &packet); - attr->size = packet.buf.idx; + attr->size = packet.buf[0].idx; /* * Find lowest level size. */ for (idx = MAX_MSG_LEVEL-1; idx; idx--) { - if (packet.bufX[idx].idx) { - attr->size += packet.bufX[idx].idx; + if (packet.buf[idx].idx) { + attr->size += packet.buf[idx].idx; break; } } diff --git a/code/lspgen/src/lspgen_lsdb.h b/code/lspgen/src/lspgen_lsdb.h index 0c0cb922..76551584 100644 --- a/code/lspgen/src/lspgen_lsdb.h +++ b/code/lspgen/src/lspgen_lsdb.h @@ -316,8 +316,7 @@ typedef struct lsdb_packet_ { uint32_t id; /* Fragment # for IS-IS, LS-Update Packet # for OSPF */ } key; - struct io_buffer_ buf; - struct io_buffer_ bufX[MAX_MSG_LEVEL]; + struct io_buffer_ buf[MAX_MSG_LEVEL]; uint8_t data[1500]; /* fixed buffer */ uint8_t redzone[8]; /* Overwrite detection */ diff --git a/code/lspgen/src/lspgen_mrt.c b/code/lspgen/src/lspgen_mrt.c index aaa38389..7f847f03 100644 --- a/code/lspgen/src/lspgen_mrt.c +++ b/code/lspgen/src/lspgen_mrt.c @@ -14,6 +14,7 @@ /* https://datatracker.ietf.org/doc/html/rfc6396#section-4 */ #define MRT_TYPE_OSPFV2 11 +#define MRT_TYPE_OSPFV3 48 #define MRT_TYPE_ISIS 32 /* @@ -62,8 +63,8 @@ lspgen_dump_mrt_node(lsdb_ctx_t *ctx, lsdb_node_t *node) /* * Copy packet */ - memcpy(&mrt_record[buf.idx], packet->data, packet->buf.idx); - buf.idx += packet->buf.idx; + memcpy(&mrt_record[buf.idx], packet->data, packet->buf[0].idx); + buf.idx += packet->buf[0].idx; break; case PROTO_OSPF2: @@ -77,13 +78,37 @@ lspgen_dump_mrt_node(lsdb_ctx_t *ctx, lsdb_node_t *node) /* * Copy packet */ - if (packet->buf.idx > 20) { + if (packet->buf[0].idx > 20) { /* * Skip 20 bytes of IPv4 header. */ - memcpy(&mrt_record[buf.idx], packet->data+20, packet->buf.idx-20); - buf.idx += packet->buf.idx-20; + memcpy(&mrt_record[buf.idx], packet->data+20, packet->buf[0].idx-20); + buf.idx += packet->buf[0].idx-20; + } + break; + + case PROTO_OSPF3: + push_be_uint(&buf, 2, MRT_TYPE_OSPFV3); /* type */ + push_be_uint(&buf, 2, 0); /* subtype */ + push_be_uint(&buf, 4, 0); /* length, will be overwritten */ + + push_be_uint(&buf, 2, 2); /* address family: ipv6 */ + push_be_uint(&buf, 8, 0); /* remote IP address */ + push_be_uint(&buf, 8, 0); /* remote IP address */ + push_be_uint(&buf, 8, 0); /* local IP address */ + push_be_uint(&buf, 8, 0); /* local IP address */ + + /* + * Copy packet + */ + if (packet->buf[0].idx > 40) { + + /* + * Skip 40 bytes of IPv6 header. + */ + memcpy(&mrt_record[buf.idx], packet->data+40, packet->buf[0].idx-40); + buf.idx += packet->buf[0].idx-40; } break; diff --git a/code/lspgen/src/lspgen_ospf.h b/code/lspgen/src/lspgen_ospf.h index 8de381b0..c5708ccb 100644 --- a/code/lspgen/src/lspgen_ospf.h +++ b/code/lspgen/src/lspgen_ospf.h @@ -15,8 +15,8 @@ #define OSPF_LSA_SUMMARY 3 #define OSPF_LSA_ASBR_SUMMARY 4 #define OSPF_LSA_EXTERNAL 5 - #define OSPF_LSA_OPAQUE_LINK 9 +#define OSPF_LSA_INTRA_AREA_PREFIX 39 /* OSPFv3 LSA Type 9*/ #define OSPF_LSA_OPAQUE_AREA_RI 104 #define OSPF_LSA_OPAQUE_AREA_EP 107 /* rfc 7684 */ #define OSPF_LSA_OPAQUE_DOMAIN 11 @@ -30,4 +30,11 @@ #define OSPF_TLV_SID_LABEL_RANGE 9 /* Opaque LSA Extended Prefix TLVs */ +#define OSPF_TLV_EXTENDED_PREFIX 12 #define OSPF_TLV_EXTENDED_PREFIX_RANGE 2 + +/* Extended Prefix & Extended Prefix range subTLVs */ +#define OSPF_SUBTLV_EXTENDED_PREFIX_SID 1 + +/* Inter Area Prefix LSA */ +#define OSPF_IA_PREFIX_LSA_PREFIX 31 diff --git a/code/lspgen/src/lspgen_packet.c b/code/lspgen/src/lspgen_packet.c index 3a6b84a5..e1e16e9c 100644 --- a/code/lspgen/src/lspgen_packet.c +++ b/code/lspgen/src/lspgen_packet.c @@ -18,49 +18,52 @@ */ void lspgen_gen_packet_node(lsdb_node_t *); void lspgen_serialize_ospf2_state(lsdb_attr_t *, lsdb_packet_t *, uint16_t); +void lspgen_serialize_ospf3_state(lsdb_attr_t *, lsdb_packet_t *, uint16_t); void lspgen_gen_isis_packet_header(lsdb_ctx_t *ctx, lsdb_node_t *node, lsdb_packet_t *packet) { + struct io_buffer_ *buf; unsigned long long sysid; uint8_t lsattr; /* * Reset buffer. */ - packet->buf.data = packet->data; - packet->buf.start_idx = 0; - packet->buf.idx = 0; - packet->buf.size = sizeof(packet->data); + buf = &packet->buf[0]; + buf->data = packet->data; + buf->start_idx = 0; + buf->idx = 0; + buf->size = sizeof(packet->data); - push_be_uint(&packet->buf, 1, 0x83); /* Intradomain Routeing Protocol Discriminator */ - push_be_uint(&packet->buf, 1, 27); /* Length Indicator always 27 for LSPs */ - push_be_uint(&packet->buf, 1, 1); /* Version/Protocol ID Extension */ - push_be_uint(&packet->buf, 1, 0); /* ID Length */ + push_be_uint(buf, 1, 0x83); /* Intradomain Routeing Protocol Discriminator */ + push_be_uint(buf, 1, 27); /* Length Indicator always 27 for LSPs */ + push_be_uint(buf, 1, 1); /* Version/Protocol ID Extension */ + push_be_uint(buf, 1, 0); /* ID Length */ /* PDU Type */ if (ctx->topology_id.level == 1) { - push_be_uint(&packet->buf, 1, ISIS_PDU_L1_LSP); + push_be_uint(buf, 1, ISIS_PDU_L1_LSP); } if (ctx->topology_id.level == 2) { - push_be_uint(&packet->buf, 1, ISIS_PDU_L2_LSP); + push_be_uint(buf, 1, ISIS_PDU_L2_LSP); } - push_be_uint(&packet->buf, 1, 1); /* Version */ - push_be_uint(&packet->buf, 1, 0); /* Reserved */ - push_be_uint(&packet->buf, 1, 0); /* Maximum Area Addresses */ + push_be_uint(buf, 1, 1); /* Version */ + push_be_uint(buf, 1, 0); /* Reserved */ + push_be_uint(buf, 1, 0); /* Maximum Area Addresses */ - push_be_uint(&packet->buf, 2, 0); /* PDU length */ - push_be_uint(&packet->buf, 2, 0); /* Remaining Lifetime - will be overwritten during checksum calc */ + push_be_uint(buf, 2, 0); /* PDU length */ + push_be_uint(buf, 2, 0); /* Remaining Lifetime - will be overwritten during checksum calc */ /* LSP ID */ sysid = read_be_uint(node->key.node_id, 6); - push_be_uint(&packet->buf, 6, sysid); /* System ID */ - push_be_uint(&packet->buf, 1, 0); /* PSN # */ - push_be_uint(&packet->buf, 1, packet->key.id); /* Fragment # */ + push_be_uint(buf, 6, sysid); /* System ID */ + push_be_uint(buf, 1, 0); /* PSN # */ + push_be_uint(buf, 1, packet->key.id); /* Fragment # */ - push_be_uint(&packet->buf, 4, node->sequence); /* Sequence */ - push_be_uint(&packet->buf, 2, 0); /* Checksum */ + push_be_uint(buf, 4, node->sequence); /* Sequence */ + push_be_uint(buf, 2, 0); /* Checksum */ lsattr = 0; if (ctx->topology_id.level == 1) { @@ -75,36 +78,7 @@ lspgen_gen_isis_packet_header(lsdb_ctx_t *ctx, lsdb_node_t *node, lsdb_packet_t if (node->attach) { lsattr |= 0x08; } - push_be_uint(&packet->buf, 1, lsattr); /* LSP Attributes */ -} - -void -lspgen_gen_ospf2_packet_header(lsdb_ctx_t *ctx, lsdb_node_t *node, lsdb_packet_t *packet) -{ - uint32_t router_id; - - /* - * Reset buffer. - */ - packet->buf.data = packet->data; - packet->buf.start_idx = 0; - packet->buf.idx = 0; - packet->buf.size = sizeof(packet->data); - - push_be_uint(&packet->buf, 1, 2); /* Version */ - push_be_uint(&packet->buf, 1, 4); /* Message Type: Link State Update */ - push_be_uint(&packet->buf, 2, 0); /* Packet length - will be overwritten later */ - - router_id = read_be_uint(node->key.node_id, 4); - push_be_uint(&packet->buf, 4, router_id); /* Router ID */ - push_be_uint(&packet->buf, 4, ctx->topology_id.area); /* Area ID */ - - push_be_uint(&packet->buf, 2, 0); /* Checksum - will be overwritten later */ - - push_be_uint(&packet->buf, 2, 0); /* Authentication Type */ - push_be_uint(&packet->buf, 8, 0); /* Authentication */ - - push_be_uint(&packet->buf, 4, 0); /* # LSAs - will be overwritten later */ + push_be_uint(buf, 1, lsattr); /* LSP Attributes */ } void @@ -115,7 +89,8 @@ 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); + break; + case PROTO_OSPF3: break; default: LOG_NOARG(ERROR, "Unknown protocol\n"); @@ -203,32 +178,46 @@ calculate_cksum(uint8_t *buf, uint16_t len) } /* - * Calculate the size of the authentication TLV to be inserted. + * Calculate the size of the authentication data to be inserted. * Helper for calculating when to start a new packet. */ uint32_t -lspgen_calculate_isis_auth_len(lsdb_ctx_t *ctx) +lspgen_calculate_auth_len(lsdb_ctx_t *ctx) { uint8_t auth_len; auth_len = 0; - if (ctx->authentication_key && ctx->authentication_type) { - if (ctx->authentication_type == ISIS_AUTH_SIMPLE) { - auth_len = strlen(ctx->authentication_key) + 1 + TLV_OVERHEAD; - } if (ctx->authentication_type == ISIS_AUTH_MD5) { - auth_len = 16 + 1 + TLV_OVERHEAD; + switch (ctx->protocol_id) { + case PROTO_ISIS: + if (ctx->authentication_key && ctx->authentication_type) { + if (ctx->authentication_type == ISIS_AUTH_SIMPLE) { + auth_len = strlen(ctx->authentication_key) + 1 + TLV_OVERHEAD; + } if (ctx->authentication_type == ISIS_AUTH_MD5) { + auth_len = 16 + 1 + TLV_OVERHEAD; + } } - } + break; + /* + * BNG Blaster computes the authentication trailer for OSPF2 and OSPF3 + */ + case PROTO_OSPF2: /* fall through */ + case PROTO_OSPF3: /* fall through */ + default: + break; + } return auth_len; } void lspgen_finalize_isis_packet(lsdb_ctx_t *ctx, lsdb_node_t *node, lsdb_packet_t *packet) { + struct io_buffer_ *buf; uint16_t checksum, lsp_lifetime; uint8_t auth_len; + buf = &packet->buf[0]; + /* * Generate Authentication TLV */ @@ -240,21 +229,21 @@ lspgen_finalize_isis_packet(lsdb_ctx_t *ctx, lsdb_node_t *node, lsdb_packet_t *p auth_len = 16; } - push_be_uint(&packet->buf, 1, ISIS_TLV_AUTH); /* Type */ - push_be_uint(&packet->buf, 1, auth_len+1); /* Length */ - push_be_uint(&packet->buf, 1, ctx->authentication_type); + push_be_uint(buf, 1, ISIS_TLV_AUTH); /* Type */ + push_be_uint(buf, 1, auth_len+1); /* Length */ + push_be_uint(buf, 1, ctx->authentication_type); if (ctx->authentication_type == ISIS_AUTH_SIMPLE) { - push_data(&packet->buf, (uint8_t *)ctx->authentication_key, auth_len); + push_data(buf, (uint8_t *)ctx->authentication_key, auth_len); } if (ctx->authentication_type == ISIS_AUTH_MD5) { - push_be_uint(&packet->buf, 8, 0); - push_be_uint(&packet->buf, 8, 0); + push_be_uint(buf, 8, 0); + push_be_uint(buf, 8, 0); /* Update PDU length field. */ - write_be_uint(packet->data+8, 2, packet->buf.idx); - hmac_md5(packet->buf.data, packet->buf.idx, + write_be_uint(packet->data+8, 2, buf->idx); + hmac_md5(buf->data, buf->idx, (unsigned char *)ctx->authentication_key, strlen(ctx->authentication_key), - packet->buf.data+packet->buf.idx-16); + buf->data+buf->idx-16); } } @@ -274,26 +263,24 @@ lspgen_finalize_isis_packet(lsdb_ctx_t *ctx, lsdb_node_t *node, lsdb_packet_t *p /* * Update PDU length field. */ - write_be_uint(packet->data+8, 2, packet->buf.idx); + write_be_uint(packet->data+8, 2, buf->idx); /* * Calculate Checksum */ - write_be_uint(packet->data+24, 2, 0); /* reset checksum field */ - checksum = calculate_fletcher_cksum(packet->data+12, 12, packet->buf.idx-12); - write_be_uint(packet->data+24, 2, checksum); + write_be_uint(buf->data+24, 2, 0); /* reset checksum field */ + checksum = calculate_fletcher_cksum(buf->data+12, 12, buf->idx-12); + write_be_uint(buf->data+24, 2, checksum); } -void -lspgen_finalize_ospf2_packet(__attribute__((unused))lsdb_ctx_t *ctx, - __attribute__((unused))lsdb_node_t *node, - lsdb_packet_t *packet) +/* + * Close all Message levels that the serializer may have left open. + */ +uint16_t +lspgen_close_all_message_levels (lsdb_packet_t *packet) { uint16_t state; - /* - * Close all Message levels that the serializer may have left open. - */ state = 0; if (packet->prev_attr_cp[0]) { state |= CLOSE_LEVEL0; @@ -304,9 +291,11 @@ lspgen_finalize_ospf2_packet(__attribute__((unused))lsdb_ctx_t *ctx, if (packet->prev_attr_cp[2]) { state |= CLOSE_LEVEL2; } - lspgen_serialize_ospf2_state(NULL, packet, state); - memcpy(&packet->buf, &packet->bufX[0], sizeof(struct io_buffer_)); /* XXX rework */ + if (packet->prev_attr_cp[3]) { + state |= CLOSE_LEVEL3; + } + return state; } void @@ -317,7 +306,10 @@ lspgen_finalize_packet(lsdb_ctx_t *ctx, lsdb_node_t *node, lsdb_packet_t *packet lspgen_finalize_isis_packet(ctx, node, packet); break; case PROTO_OSPF2: - lspgen_finalize_ospf2_packet(ctx, node, packet); + lspgen_serialize_ospf2_state(NULL, packet, lspgen_close_all_message_levels(packet)); + break; + case PROTO_OSPF3: + lspgen_serialize_ospf3_state(NULL, packet, lspgen_close_all_message_levels(packet)); break; default: LOG_NOARG(ERROR, "Unknown protocol\n"); @@ -449,7 +441,7 @@ lspgen_serialize_isis_attr(lsdb_attr_t *attr, lsdb_packet_t *packet) bool subtlv_present; io_buffer_t *buf; - buf = &packet->buf; + buf = &packet->buf[0]; subtlv_present = lsdb_attr_subtlvs_present(attr); @@ -620,8 +612,8 @@ lspgen_propagate_buffer_down (lsdb_packet_t *packet, uint level) return; } - cur = &packet->bufX[level]; - next = &packet->bufX[level+1]; + cur = &packet->buf[level]; + next = &packet->buf[level+1]; next->data = cur->data + cur->idx; next->size = cur->size - cur->idx; @@ -642,8 +634,8 @@ lspgen_propagate_buffer_up (lsdb_packet_t *packet, uint level) return; } - cur = &packet->bufX[level]; - prev = &packet->bufX[level-1]; + cur = &packet->buf[level]; + prev = &packet->buf[level-1]; prev->idx += cur->idx; cur->data += cur->idx; @@ -741,29 +733,47 @@ lspgen_serialize_ospf2_state(lsdb_attr_t *attr, lsdb_packet_t *packet, uint16_t { lsdb_ctx_t *ctx; lsdb_node_t *node; - io_buffer_t *buf0, *buf1, *buf2; + io_buffer_t *buf0, *buf1, *buf2, *buf3; uint16_t attr_len, checksum; uint32_t router_id, mask; node = packet->parent; ctx = node->ctx; - buf0 = &packet->bufX[0]; - buf1 = &packet->bufX[1]; - buf2 = &packet->bufX[2]; + buf0 = &packet->buf[0]; + buf1 = &packet->buf[1]; + buf2 = &packet->buf[2]; + buf3 = &packet->buf[3]; LOG(PACKET, " %s\n", lspgen_format_serializer_state(state)); - /* close Level 2 */ - if (state & CLOSE_LEVEL2) { - switch (packet->prev_attr_cp[2]) { - case OSPF_ROUTER_LSA_LINK_PTP: - case OSPF_ROUTER_LSA_LINK_STUB: + /* close Level 3 */ + if (state & CLOSE_LEVEL3) { + switch (packet->prev_attr_cp[3]) { + case OSPF_SUBTLV_EXTENDED_PREFIX_SID: + write_be_uint(buf3->data+2, 2, buf3->idx-4); /* Update length */ + push_pad4(buf3); break; default: break; } + lspgen_propagate_buffer_up(packet, 3); + } + + /* close Level 2 */ + if (state & CLOSE_LEVEL2) { + switch (packet->prev_attr_cp[2]) { + case OSPF_TLV_EXTENDED_PREFIX_RANGE: /* fall through */ + case OSPF_TLV_EXTENDED_PREFIX: + case OSPF_TLV_SID_LABEL_RANGE: + write_be_uint(buf2->data+2, 2, buf2->idx-4); /* Update length */ + push_pad4(buf2); + default: + break; + } + + lspgen_propagate_buffer_up(packet, 2); } @@ -791,7 +801,6 @@ lspgen_serialize_ospf2_state(lsdb_attr_t *attr, lsdb_packet_t *packet, uint16_t /* close Level 0 */ if (state & CLOSE_LEVEL0) { - switch (packet->prev_attr_cp[0]) { case OSPF_MSG_LSUPDATE: write_be_uint(buf0->data+20+2, 2, buf0->idx - 20); /* Packet length */ @@ -838,7 +847,6 @@ lspgen_serialize_ospf2_state(lsdb_attr_t *attr, lsdb_packet_t *packet, uint16_t push_be_uint(buf0, 8, 0); /* Authentication */ push_be_uint(buf0, 4, 0); /* # LSAs - will be overwritten later */ - break; default: LOG(ERROR, "No Level 0 open packet serializer for attr %d\n", attr->key.attr_cp[0]); @@ -967,6 +975,296 @@ lspgen_serialize_ospf2_state(lsdb_attr_t *attr, lsdb_packet_t *packet, uint16_t } break; + case OSPF_TLV_SID_LABEL_RANGE: + if (attr->key.cap.srgb_base && attr->key.cap.srgb_range) { + push_be_uint(buf2, 2, 9); /* Type */ + push_be_uint(buf2, 2, 0); /* Length - will be overwritten later */ + push_be_uint(buf2, 3, attr->key.cap.srgb_range); /* Range size */ + push_be_uint(buf2, 1, 0); /* Reserved */ + + /* XXX Move this to level 3 */ + push_be_uint(buf2, 2, 1); /* SID Type Label */ + push_be_uint(buf2, 2, 3); /* SID Type Length */ + push_be_uint(buf2, 3, attr->key.cap.srgb_base); + push_pad4(buf2); + } + break; + + case OSPF_TLV_EXTENDED_PREFIX_RANGE: + push_be_uint(buf2, 2, 2); /* Type */ + push_be_uint(buf2, 2, 0); /* Length - will be overwritten later */ + push_be_uint(buf2, 1, attr->key.prefix.ipv4_prefix.len); + push_be_uint(buf2, 1, 0); /* AF ipv4 */ + push_be_uint(buf2, 2, 1); /* Range size */ + push_be_uint(buf2, 1, 0); /* Flags */ + push_be_uint(buf2, 3, 0); /* Reserved */ + push_data(buf2, (uint8_t*)&attr->key.prefix.ipv4_prefix.address, 4); /* Prefix */ + break; + + case OSPF_TLV_EXTENDED_PREFIX: + push_be_uint(buf2, 2, 1); /* Type */ + push_be_uint(buf2, 2, 0); /* Length - will be overwritten later */ + push_be_uint(buf2, 1, 1); /* Route Type: Intra Area */ + push_be_uint(buf2, 1, attr->key.prefix.ipv4_prefix.len); + push_be_uint(buf2, 1, 0); /* AF ipv4 */ + push_be_uint(buf2, 1, 0); /* Flags */ + push_data(buf2, (uint8_t*)&attr->key.prefix.ipv4_prefix.address, 4); /* Prefix */ + break; + + default: + LOG(ERROR, "No Level 2 open packet serializer for attr %d\n", attr->key.attr_cp[2]); + return; + } + + lspgen_propagate_buffer_down(packet, 2); + } + + /* open Level 3 */ + if (state & OPEN_LEVEL3) { + switch(attr->key.attr_cp[3]) { + case OSPF_SUBTLV_EXTENDED_PREFIX_SID: + push_be_uint(buf3, 2, 2); /* Type */ + push_be_uint(buf3, 2, 0); /* Length - will be overwritten later */ + push_be_uint(buf3, 3, 0); /* Flags, Reserved, MT-ID */ + push_be_uint(buf3, 1, attr->key.prefix.sid_algo); /* Algorithm */ + push_be_uint(buf3, 4, attr->key.prefix.sid); /* SID Index */ + break; + + default: + LOG(ERROR, "No Level 3 open packet serializer for attr %d\n", attr->key.attr_cp[3]); + return; + } + + lspgen_propagate_buffer_down(packet, 3); + } + +} + +void +lspgen_serialize_ospf3_state(lsdb_attr_t *attr, lsdb_packet_t *packet, uint16_t state) +{ + lsdb_ctx_t *ctx; + lsdb_node_t *node; + io_buffer_t *buf0, *buf1, *buf2; + uint16_t attr_len, checksum; + uint32_t router_id; + + node = packet->parent; + ctx = node->ctx; + + buf0 = &packet->buf[0]; + buf1 = &packet->buf[1]; + buf2 = &packet->buf[2]; + + LOG(PACKET, " %s\n", lspgen_format_serializer_state(state)); + + /* close Level 2 */ + if (state & CLOSE_LEVEL2) { + lspgen_propagate_buffer_up(packet, 2); + } + + /* close Level 1 */ + if (state & CLOSE_LEVEL1) { + switch (packet->prev_attr_cp[1]) { + case OSPF_LSA_ROUTER: + case OSPF_LSA_EXTERNAL: + case OSPF_LSA_OPAQUE_AREA_RI: + case OSPF_LSA_OPAQUE_AREA_EP: + case OSPF_LSA_INTRA_AREA_PREFIX: + inc_be_uint(buf0->data+40+16, 4); /* Update #LSAs */ + write_be_uint(buf1->data+18, 2, buf1->idx); /* Update Packet length */ + write_be_uint(buf1->data+16, 2, 0); /* reset checksum field */ + checksum = calculate_fletcher_cksum(buf1->data+2, 14, buf1->idx-2); + write_be_uint(buf1->data+16, 2, checksum); /* Update LSA Checksum */ + break; + default: + break; + } + + lspgen_propagate_buffer_up(packet, 1); + } + + /* close Level 0 */ + if (state & CLOSE_LEVEL0) { + switch (packet->prev_attr_cp[0]) { + case OSPF_MSG_LSUPDATE: + write_be_uint(buf0->data+40+2, 2, buf0->idx - 40); /* Packet length */ + write_be_uint(buf0->data+40+12, 2, calculate_cksum(buf0->data+40, buf0->idx-40)); /* Checksum */ + write_be_uint(buf0->data+4, 2, buf0->idx - 40); /* Payload length */ + break; + default: + break; + } + } + + /* open Level 0 */ + if (state & OPEN_LEVEL0) { + + switch(attr->key.attr_cp[0]) { + case OSPF_MSG_LSUPDATE: + + /* IPv6 header */ + push_be_uint(buf0, 1, 0x6c); /* Version, Traffic Class MSB */ + push_be_uint(buf0, 3, 0); /* Flow label */ + push_be_uint(buf0, 2, 0); /* Payload length - will be overwritten later */ + push_be_uint(buf0, 1, 89); /* Next Header */ + push_be_uint(buf0, 1, 255); /* Hop limit */ + push_data(buf0, (uint8_t *)&ctx->ipv6_node_prefix.address, IPV6_ADDR_LEN); /* Source Address */ + push_be_uint(buf0, 8, 0xff02000000000000); /* Destination Address */ + push_be_uint(buf0, 8, 5); /* Destination Address */ + + /* OSPFv3 header */ + push_be_uint(buf0, 1, 3); /* 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, ctx->topology_id.area); /* Area ID */ + + push_be_uint(buf0, 2, 0); /* Checksum - will be overwritten later */ + + push_be_uint(buf0, 1, 0); /* Instance ID */ + push_be_uint(buf0, 1, 0); /* Reserved */ + + push_be_uint(buf0, 4, 0); /* # LSAs - will be overwritten later */ + break; + default: + LOG(ERROR, "No Level 0 open packet serializer for attr %d\n", attr->key.attr_cp[0]); + return; + } + + lspgen_propagate_buffer_down(packet, 0); + } + + /* open Level 1 */ + if (state & OPEN_LEVEL1) { + + switch(attr->key.attr_cp[1]) { + case OSPF_LSA_ROUTER: + push_be_uint(buf1, 2, lspgen_get_ospf_age(node)); /* LS-age */ + push_be_uint(buf1, 2, 0x2001); /* 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(buf1, 4, node->sequence); /* Sequence */ + push_be_uint(buf1, 2, 0xffff); /* 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, 3, 0); /* Options */ + break; + + case OSPF_LSA_EXTERNAL: + push_be_uint(buf1, 2, lspgen_get_ospf_age(node)); /* LS-age */ + push_be_uint(buf1, 2, 0x4005); /* 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(buf1, 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, 0x04); /* E2 */ + push_be_uint(buf1, 3, attr->key.prefix.metric); /* Metric */ + push_be_uint(buf1, 1, attr->key.prefix.ipv6_prefix.len); /* Prefix Length */ + push_be_uint(buf1, 1, 0x00); /* Prefix Options */ + push_be_uint(buf1, 2, 0); /* Referenced LS Type */ + attr_len = (attr->key.prefix.ipv6_prefix.len+7)/8; + push_data(buf1, attr->key.prefix.ipv6_prefix.address, attr_len); /* Prefix */ + push_pad4(buf1); + break; + + case OSPF_LSA_INTRA_AREA_PREFIX: + push_be_uint(buf1, 2, lspgen_get_ospf_age(node)); /* LS-age */ + push_be_uint(buf1, 2, 0x2009); /* 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(buf1, 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, 2, 0); /* # Prefixes - will be overwritten later */ + push_be_uint(buf1, 2, 0x2001); /* # Referenced LS Type */ + + push_be_uint(buf1, 4, 0); /* Referenced Link State ID */ + push_be_uint(buf1, 4, router_id); /* Referenced Advertising Router */ + + break; + + case OSPF_LSA_OPAQUE_AREA_RI: + push_be_uint(buf1, 2, lspgen_get_ospf_age(node)); /* LS-age */ + push_be_uint(buf1, 2, 0x800c); /* LS-Type */ + push_be_uint(buf1, 4, 0); /* Link State ID (Instance ID) */ + router_id = read_be_uint(node->key.node_id, 4); + push_be_uint(buf1, 4, router_id); /* Advertising Router */ + push_be_uint(buf1, 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 */ + break; + + case OSPF_LSA_OPAQUE_AREA_EP: + push_be_uint(buf1, 2, lspgen_get_ospf_age(node)); /* LS-age */ + push_be_uint(buf1, 1, 0); /* Options */ + push_be_uint(buf1, 1, 10); /* LS-Type */ + push_be_uint(buf1, 1, 7); /* Opaque Type: Extended Prefix */ + 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(buf1, 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 */ + break; + + default: + LOG(ERROR, "No Level 1 open packet serializer for attr %d\n", attr->key.attr_cp[1]); + return; + } + + lspgen_propagate_buffer_down(packet, 1); + } + + /* + * If users wants to generate purges encoding stops at level 1. + */ + if (ctx->purge) { + return; + } + + /* open Level 2 */ + if (state & OPEN_LEVEL2) { + switch(attr->key.attr_cp[2]) { + case OSPF_ROUTER_LSA_LINK_PTP: + push_be_uint(buf2, 1, 1); /* Type ptp */ + push_be_uint(buf2, 1, 0); /* #TOS */ + push_be_uint(buf2, 2, attr->key.link.metric); /* metric */ + push_be_uint(buf2, 4, read_be_uint(attr->key.link.local_node_id, 4)); /* Interface ID */ + push_be_uint(buf2, 4, 0); /* Neighbor Interface ID */ + push_be_uint(buf2, 4, read_be_uint(attr->key.link.remote_node_id, 4)); /* Neighbor Router ID */ + break; + + case OSPF_IA_PREFIX_LSA_PREFIX: + push_be_uint(buf2, 1, attr->key.prefix.ipv6_prefix.len); /* Prefix Length */ + push_be_uint(buf2, 1, 0x00); /* Prefix Options */ + push_be_uint(buf2, 2, attr->key.prefix.metric); /* Metric */ + attr_len = (attr->key.prefix.ipv6_prefix.len+7)/8; + push_data(buf2, attr->key.prefix.ipv6_prefix.address, attr_len); /* Prefix */ + push_pad4(buf2); + + inc_be_uint(buf1->data+20, 2); /* Update #prefixes */ + 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_pad4(buf2); + } + break; + case OSPF_TLV_SID_LABEL_RANGE: if (attr->key.cap.srgb_base && attr->key.cap.srgb_range) { push_be_uint(buf2, 2, 9); /* Type */ @@ -1002,7 +1300,7 @@ lspgen_serialize_ospf2_state(lsdb_attr_t *attr, lsdb_packet_t *packet, uint16_t push_be_uint(buf2, 4, attr->key.prefix.sid); /* SID Index */ push_pad4(buf2); - write_be_uint(buf2->data+2, 2, buf2->idx-4); /* Update length */ + //write_be_uint(buf2->data+2, 2, buf2->idx-4); /* Update length */ push_pad4(buf2); break; @@ -1016,10 +1314,12 @@ lspgen_serialize_ospf2_state(lsdb_attr_t *attr, lsdb_packet_t *packet, uint16_t } /* - * Serialize an OSPFv2 attribute into a packet buffer. + * Serialize an OSPF attribute into a packet buffer. + * Pass a custom serialization callback function. */ void -lspgen_serialize_ospf2_attr(lsdb_attr_t *attr, lsdb_packet_t *packet) +lspgen_serialize_ospf_attr(lsdb_attr_t *attr, lsdb_packet_t *packet, + void (*serialize_cb)(lsdb_attr_t *, lsdb_packet_t *, uint16_t)) { uint16_t state; @@ -1043,9 +1343,12 @@ lspgen_serialize_ospf2_attr(lsdb_attr_t *attr, lsdb_packet_t *packet) state |= OPEN_LEVEL1; if (attr->key.attr_cp[2] && packet->prev_attr_cp[2] == 0) { state |= OPEN_LEVEL2; + if (attr->key.attr_cp[3] && packet->prev_attr_cp[3] == 0) { + state |= OPEN_LEVEL3; + } } } - lspgen_serialize_ospf2_state(attr, packet, state); + (*serialize_cb)(attr, packet, state); return; } @@ -1057,6 +1360,12 @@ lspgen_serialize_ospf2_attr(lsdb_attr_t *attr, lsdb_packet_t *packet) if (attr->key.attr_cp[0]) { state |= OPEN_LEVEL0; } + if (packet->prev_attr_cp[3]) { + state |= CLOSE_LEVEL3; + } + if (attr->key.attr_cp[3]) { + state |= OPEN_LEVEL3; + } if (packet->prev_attr_cp[2]) { state |= CLOSE_LEVEL2; } @@ -1069,7 +1378,7 @@ lspgen_serialize_ospf2_attr(lsdb_attr_t *attr, lsdb_packet_t *packet) if (attr->key.attr_cp[1]) { state |= OPEN_LEVEL1; } - lspgen_serialize_ospf2_state(attr, packet, state); + (*serialize_cb)(attr, packet, state); return; } @@ -1087,7 +1396,13 @@ lspgen_serialize_ospf2_attr(lsdb_attr_t *attr, lsdb_packet_t *packet) if (attr->key.attr_cp[2]) { state |= OPEN_LEVEL2; } - lspgen_serialize_ospf2_state(attr, packet, state); + if (packet->prev_attr_cp[3]) { + state |= CLOSE_LEVEL3; + } + if (attr->key.attr_cp[3]) { + state |= OPEN_LEVEL3; + } + (*serialize_cb)(attr, packet, state); return; } @@ -1099,7 +1414,25 @@ lspgen_serialize_ospf2_attr(lsdb_attr_t *attr, lsdb_packet_t *packet) if (attr->key.attr_cp[2]) { state |= OPEN_LEVEL2; } - lspgen_serialize_ospf2_state(attr, packet, state); + if (packet->prev_attr_cp[3]) { + state |= CLOSE_LEVEL3; + } + if (attr->key.attr_cp[3]) { + state |= OPEN_LEVEL3; + } + (*serialize_cb)(attr, packet, state); + return; + } + + /* + * Different L3 message ? + */ + if (packet->prev_attr_cp[3] != attr->key.attr_cp[3]) { + state |= CLOSE_LEVEL3; + if (attr->key.attr_cp[3]) { + state |= OPEN_LEVEL3; + } + (*serialize_cb)(attr, packet, state); return; } @@ -1111,7 +1444,9 @@ lspgen_serialize_ospf2_attr(lsdb_attr_t *attr, lsdb_packet_t *packet) /* * Figure out max level. */ - if (attr->key.attr_cp[2]) { + if (attr->key.attr_cp[3]) { + state |= OPEN_LEVEL3; + } else if (attr->key.attr_cp[2]) { state |= OPEN_LEVEL2; } else if (attr->key.attr_cp[1]) { state |= OPEN_LEVEL1; @@ -1126,7 +1461,7 @@ lspgen_serialize_ospf2_attr(lsdb_attr_t *attr, lsdb_packet_t *packet) state |= state << 8; } - lspgen_serialize_ospf2_state(attr, packet, state); + (*serialize_cb)(attr, packet, state); return; } } @@ -1146,7 +1481,10 @@ lspgen_serialize_attr(lsdb_ctx_t *ctx, lsdb_attr_t *attr, lsdb_packet_t *packet) lspgen_serialize_isis_attr(attr, packet); break; case PROTO_OSPF2: - lspgen_serialize_ospf2_attr(attr, packet); + lspgen_serialize_ospf_attr(attr, packet, lspgen_serialize_ospf2_state); + break; + case PROTO_OSPF3: + lspgen_serialize_ospf_attr(attr, packet, lspgen_serialize_ospf3_state); break; default: LOG_NOARG(ERROR, "Unknown protocol\n"); @@ -1189,14 +1527,17 @@ lspgen_calculate_tlv_space(io_buffer_t *buf, uint32_t tlv_start_idx) void lspgen_reset_packet_buffer (struct lsdb_packet_ *packet) { + struct io_buffer_ *buf; 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_)); + buf = &packet->buf[0]; + + buf->data = packet->data; + buf->start_idx = 0; + buf->idx = 0; + buf->size = sizeof(packet->data); + for (idx = 1; idx < MAX_MSG_LEVEL; idx++) { + memcpy(&packet->buf[idx], buf, sizeof(struct io_buffer_)); } /* @@ -1377,9 +1718,9 @@ lspgen_gen_isis_packet_node(lsdb_node_t *node) /* * Space left in this packet ? */ - min_len = lspgen_calculate_isis_auth_len(ctx); + min_len = lspgen_calculate_auth_len(ctx); min_len += attr->size + TLV_OVERHEAD; - if (packet && packet->buf.idx > (1465-min_len)) { + if (packet && packet->buf[0].idx > (1465-min_len)) { /* * No space left. Finalize this packet. @@ -1400,7 +1741,7 @@ lspgen_gen_isis_packet_node(lsdb_node_t *node) */ if (!packet) { packet = lspgen_add_packet(ctx, node, id); - tlv_start_idx = packet->buf.idx; + tlv_start_idx = packet->buf[0].idx; } /* @@ -1411,15 +1752,15 @@ lspgen_gen_isis_packet_node(lsdb_node_t *node) * Start a fresh TLV ? */ if ((last_attr != attr->key.attr_type) || - (lspgen_calculate_tlv_space(&packet->buf, tlv_start_idx) < attr->size) || + (lspgen_calculate_tlv_space(&packet->buf[0], 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 */ + tlv_start_idx = packet->buf[0].idx; + push_be_uint(&packet->buf[0], 1, attr->key.attr_type); /* Type */ + push_be_uint(&packet->buf[0], 1, 0); /* Length */ } lspgen_serialize_attr(ctx, attr, packet); - lspgen_update_tlv_length(&packet->buf, tlv_start_idx); + lspgen_update_tlv_length(&packet->buf[0], tlv_start_idx); last_attr = attr->key.attr_type; @@ -1430,10 +1771,10 @@ lspgen_gen_isis_packet_node(lsdb_node_t *node) } /* - * Walk the graph of the LSDB and serialize OSPFv2 packets. + * Walk the graph of the LSDB and serialize OSPF2 and OSPF3 packets. */ void -lspgen_gen_ospf2_packet_node(lsdb_node_t *node) +lspgen_gen_ospf_packet_node(lsdb_node_t *node) { lsdb_ctx_t *ctx; struct lsdb_packet_ *packet; @@ -1491,9 +1832,9 @@ lspgen_gen_ospf2_packet_node(lsdb_node_t *node) /* * Space left in this packet ? */ - min_len = lspgen_calculate_isis_auth_len(ctx); + min_len = lspgen_calculate_auth_len(ctx); min_len += attr->size; - if (packet && packet->bufX[0].idx > (1440-min_len)) { + if (packet && packet->buf[0].idx > (1440-min_len)) { /* * No space left. Finalize this packet. @@ -1537,8 +1878,9 @@ lspgen_gen_packet_node(lsdb_node_t *node) case PROTO_ISIS: lspgen_gen_isis_packet_node(node); break; - case PROTO_OSPF2: - lspgen_gen_ospf2_packet_node(node); + case PROTO_OSPF2: /* fall through */ + case PROTO_OSPF3: + lspgen_gen_ospf_packet_node(node); break; default: LOG_NOARG(ERROR, "Unknown protocol\n"); diff --git a/code/lspgen/src/lspgen_pcap.c b/code/lspgen/src/lspgen_pcap.c index 69716591..49e52e7b 100644 --- a/code/lspgen/src/lspgen_pcap.c +++ b/code/lspgen/src/lspgen_pcap.c @@ -161,13 +161,13 @@ lspgen_dump_pcap_node (struct lsdb_ctx_ *ctx, struct lsdb_node_ *node) /* Account for the the faked ethernet & LLC header */ eth_header_length = 17; - push_le_uint(&buf, 4, packet->buf.idx+eth_header_length); /* captured packet length */ - push_le_uint(&buf, 4, packet->buf.idx+eth_header_length); /* original packet length */ + push_le_uint(&buf, 4, packet->buf[0].idx+eth_header_length); /* captured packet length */ + push_le_uint(&buf, 4, packet->buf[0].idx+eth_header_length); /* original packet length */ /* Fake an Ethernet & LLC header */ push_be_uint(&buf, 6, 0x0180c2000014); /* Destination MAC */ push_be_uint(&buf, 6, 0xf41e5e000000); /* Source MAC MAC */ - push_be_uint(&buf, 2, packet->buf.idx+3); /* Length + DSAP, SSAP, Mode */ + push_be_uint(&buf, 2, packet->buf[0].idx+3); /* Length + DSAP, SSAP, Mode */ push_be_uint(&buf, 3, 0xfefe03); /* OSI DSAP, SSAP, Mode */ } else if (ctx->protocol_id == PROTO_OSPF2) { @@ -176,8 +176,8 @@ lspgen_dump_pcap_node (struct lsdb_ctx_ *ctx, struct lsdb_node_ *node) /* Account for the faked Ethernet header */ eth_header_length = 14; - push_le_uint(&buf, 4, packet->buf.idx+eth_header_length); /* captured packet length */ - push_le_uint(&buf, 4, packet->buf.idx+eth_header_length); /* original packet length */ + push_le_uint(&buf, 4, packet->buf[0].idx+eth_header_length); /* captured packet length */ + push_le_uint(&buf, 4, packet->buf[0].idx+eth_header_length); /* original packet length */ /* Fake an Ethernet header */ push_be_uint(&buf, 6, 0x01005e000005); /* Destination MAC */ @@ -190,8 +190,8 @@ lspgen_dump_pcap_node (struct lsdb_ctx_ *ctx, struct lsdb_node_ *node) /* Account for the faked Ethernet header */ eth_header_length = 14; - push_le_uint(&buf, 4, packet->buf.idx+eth_header_length); /* captured packet length */ - push_le_uint(&buf, 4, packet->buf.idx+eth_header_length); /* original packet length */ + push_le_uint(&buf, 4, packet->buf[0].idx+eth_header_length); /* captured packet length */ + push_le_uint(&buf, 4, packet->buf[0].idx+eth_header_length); /* original packet length */ /* Fake an Ethernet header */ push_be_uint(&buf, 6, 0x333300000005); /* Destination MAC */ @@ -202,9 +202,9 @@ lspgen_dump_pcap_node (struct lsdb_ctx_ *ctx, struct lsdb_node_ *node) /* * Copy packet */ - memcpy(&pcap_packet[buf.idx], packet->data, packet->buf.idx); - buf.idx += packet->buf.idx; - push_le_uint(&buf, calc_pad(packet->buf.idx+eth_header_length), 0); /* write pad bytes */ + memcpy(&pcap_packet[buf.idx], packet->data, packet->buf[0].idx); + buf.idx += packet->buf[0].idx; + push_le_uint(&buf, calc_pad(packet->buf[0].idx+eth_header_length), 0); /* write pad bytes */ /* * Calculate total length field. It occurs twice. Overwrite and append.