diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2014-11-03 10:42:55 +0100 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2014-11-03 10:42:55 +0100 |
commit | 6f8bbaa10bbd21729d0b62a5878febcbee2c0811 (patch) | |
tree | 5b20f464388a529084e53b24406b99df2210264d /proto | |
parent | 88a183c6c9a2b86b52f67e87bbc8b7edd32670c6 (diff) |
Fininshing integrated OSPF.
Diffstat (limited to 'proto')
-rw-r--r-- | proto/ospf/dbdes.c | 47 | ||||
-rw-r--r-- | proto/ospf/hello.c | 7 | ||||
-rw-r--r-- | proto/ospf/iface.c | 33 | ||||
-rw-r--r-- | proto/ospf/lsack.c | 21 | ||||
-rw-r--r-- | proto/ospf/lsreq.c | 25 | ||||
-rw-r--r-- | proto/ospf/lsupd.c | 232 | ||||
-rw-r--r-- | proto/ospf/neighbor.c | 187 | ||||
-rw-r--r-- | proto/ospf/ospf.c | 16 | ||||
-rw-r--r-- | proto/ospf/ospf.h | 12 | ||||
-rw-r--r-- | proto/ospf/packet.c | 5 | ||||
-rw-r--r-- | proto/ospf/topology.c | 27 |
11 files changed, 374 insertions, 238 deletions
diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index 88c87164..65bdb3ec 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -212,17 +212,6 @@ ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n) ospf_prepare_dbdes(p, n); ospf_do_send_dbdes(p, n); - - if (n->state == NEIGHBOR_EXSTART) - return; - - /* Master should restart RXMT timer for each DBDES exchange */ - if (n->myimms & DBDES_MS) - tm_start(n->rxmt_timer, n->ifa->rxmtint); - - if (!(n->myimms & DBDES_MS)) - if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M)) - ospf_neigh_sm(n, INM_EXDONE); } void @@ -277,13 +266,20 @@ ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_ne en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type); if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER)) { + /* This should be splitted to ospf_lsa_lsrq_up() */ req = ospf_hash_get(n->lsrqh, lsa_domain, lsa.id, lsa.rt, lsa_type); if (!SNODE_VALID(req)) s_add_tail(&n->lsrql, SNODE req); + if (!SNODE_VALID(n->lsrqi)) + n->lsrqi = req; + req->lsa = lsa; req->lsa_body = LSA_BODY_DUMMY; + + if (!tm_active(n->lsrq_timer)) + tm_start(n->lsrq_timer, 0); } } @@ -306,13 +302,16 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, u32 rcv_ddseq, rcv_options; u16 rcv_iface_mtu; u8 rcv_imms; - uint plen, err_val = 0, err_seqmis = 0; + uint plen, err_val = 0; /* RFC 2328 10.6 */ plen = ntohs(pkt->length); if (plen < ospf_dbdes_hdrlen(p)) - DROP("too short", plen); + { + LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", plen); + return; + } OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet received from nbr %R on %s", n->rid, ifa->ifname); @@ -366,6 +365,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, n->options = rcv_options; n->myimms &= ~DBDES_MS; n->imms = rcv_imms; + tm_stop(n->dbdes_timer); ospf_neigh_sm(n, INM_NEGDONE); ospf_send_dbdes(p, n); break; @@ -381,6 +381,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, n->ddr = rcv_ddseq - 1; /* It will be set corectly a few lines down */ n->imms = rcv_imms; ospf_neigh_sm(n, INM_NEGDONE); + /* Continue to the NEIGHBOR_EXCHANGE case */ } else { @@ -394,9 +395,6 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, (rcv_ddseq == n->ddr)) goto duplicate; - /* Do INM_SEQMIS during packet error */ - err_seqmis = 1; - if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS)) DROP("MS-bit mismatch", rcv_imms); @@ -422,9 +420,14 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, return; if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M)) + { + tm_stop(n->dbdes_timer); ospf_neigh_sm(n, INM_EXDONE); - else - ospf_send_dbdes(p, n); + break; + } + + ospf_send_dbdes(p, n); + tm_start(n->dbdes_timer, n->ifa->rxmtint); } else { @@ -440,6 +443,9 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, return; ospf_send_dbdes(p, n); + + if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M)) + ospf_neigh_sm(n, INM_EXDONE); } break; @@ -450,8 +456,6 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, (rcv_ddseq == n->ddr)) goto duplicate; - err_seqmis = 1; - DROP("too late for DD exchange", n->state); default: @@ -471,7 +475,6 @@ drop: LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, err_dsc, err_val); - if (err_seqmis) - ospf_neigh_sm(n, INM_SEQMIS); + ospf_neigh_sm(n, INM_SEQMIS); return; } diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index e8b1c702..50cf1407 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -304,11 +304,8 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, nn->found = 1; } - // XXXX format - // "ospf1: New neighbor found: 192.168.1.1/fe80:1234:1234:1234:1234 on eth0"; - // "ospf1: New neighbor found: 192.168.1.1 on eth0 at fe80:1234:1234:1234:1234"; - // "ospf1: Neighbor 192.168.1.1 on eth0 found, IP adress fe80:1234:1234:1234:1234"; - OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr, ifa->ifname); + OSPF_TRACE(D_EVENTS, "New neighbor %R on %s, IP address %I", + rcv_rid, ifa->ifname, faddr); n = ospf_neighbor_new(ifa); diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index e14f09cb..4dfb74fb 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -58,6 +58,12 @@ ifa_bufsize(struct ospf_iface *ifa) return MAX(bsize, ifa->tx_length); } +static inline uint +ifa_flood_queue_size(struct ospf_iface *ifa) +{ + return ifa->tx_length / 24; +} + int ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen) { @@ -476,6 +482,9 @@ ospf_iface_add(struct object_lock *lock) if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA)) ifa->wait_timer = tm_new_set(ifa->pool, wait_timer_hook, ifa, 0, 0); + + ifa->flood_queue_size = ifa_flood_queue_size(ifa); + ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *)); } /* Do iface UP, unless there is no link and we use link detection */ @@ -679,6 +688,9 @@ ospf_iface_new_vlink(struct ospf_proto *p, struct ospf_iface_patt *ip) add_tail(&p->iface_list, NODE ifa); ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint); + + ifa->flood_queue_size = ifa_flood_queue_size(ifa); + ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *)); } static void @@ -693,6 +705,20 @@ ospf_iface_change_timer(timer *tm, uint val) tm_start(tm, val); } +static inline void +ospf_iface_update_flood_queue_size(struct ospf_iface *ifa) +{ + uint old_size = ifa->flood_queue_size; + uint new_size = ifa_flood_queue_size(ifa); + + if (new_size <= old_size) + return; + + ifa->flood_queue_size = new_size; + ifa->flood_queue = mb_realloc(ifa->flood_queue, new_size * sizeof(void *)); + bzero(ifa->flood_queue + old_size, (new_size - old_size) * sizeof(void *)); +} + int ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) { @@ -739,6 +765,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) ifname, ifa->rxmtint, new->rxmtint); ifa->rxmtint = new->rxmtint; + /* FIXME: Update neighbors' timers */ } /* POLL TIMER */ @@ -874,6 +901,9 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* ifa cannot be vlink */ ifa->tx_length = ifa_tx_length(ifa); update_buffers = 1; + + if (!ifa->stub) + ospf_iface_update_flood_queue_size(ifa); } /* RX BUFFER */ @@ -1211,6 +1241,9 @@ ospf_iface_change_mtu(struct ospf_proto *p, struct ospf_iface *ifa) sk_set_rbsize(ifa->sk, bsize); if (bsize > ifa->sk->tbsize) sk_set_tbsize(ifa->sk, bsize); + + if (!ifa->stub) + ospf_iface_update_flood_queue_size(ifa); } static void diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c index e590817e..251b5e47 100644 --- a/proto/ospf/lsack.c +++ b/proto/ospf/lsack.c @@ -162,23 +162,20 @@ ospf_receive_lsack(struct ospf_packet *pkt, struct ospf_iface *ifa, if (lsa_comp(&lsa, &ret->lsa) != CMP_SAME) { - OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip); - OSPF_TRACE(D_PACKETS, "Type: %04x, Id: %R, Rt: %R", + OSPF_TRACE(D_PACKETS, "Strange LSACK from nbr %R on %s", n->rid, ifa->ifname); + OSPF_TRACE(D_PACKETS, " Type: %04x, Id: %R, Rt: %R", lsa_type, lsa.id, lsa.rt); - OSPF_TRACE(D_PACKETS, "I have: Age: %4u, Seq: %08x, Sum: %04x", - ret->lsa.age, ret->lsa.sn, ret->lsa.checksum); - OSPF_TRACE(D_PACKETS, "He has: Age: %4u, Seq: %08x, Sum: %04x", - lsa.age, lsa.sn, lsa.checksum); + OSPF_TRACE(D_PACKETS, " I have: Seq: %08x, Age: %4u, Sum: %04x", + ret->lsa.sn, ret->lsa.age, ret->lsa.checksum); + OSPF_TRACE(D_PACKETS, " It has: Seq: %08x, Age: %4u, Sum: %04x", + lsa.sn, lsa.age, lsa.checksum); continue; } - en = ospf_hash_find_entry(p->gr, ret); - if (en) - en->ret_count--; - DBG("Deleting LSA (Type: %04x Id: %R Rt: %R) from lsrtl for neighbor %R\n", lsa_type, lsa.id, lsa.rt, n->rid); - s_rem_node(SNODE ret); - ospf_hash_delete(n->lsrth, ret); + + en = ospf_hash_find_entry(p->gr, ret); + ospf_lsa_lsrt_down_(en, n, ret); } } diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c index 067ad79b..657c0247 100644 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@ -54,42 +54,37 @@ ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n) { struct ospf_iface *ifa = n->ifa; struct ospf_lsreq_header *lsrs; - struct top_hash_entry *en; + struct top_hash_entry *req; struct ospf_packet *pkt; uint i, lsr_max, length; /* RFC 2328 10.9 */ - if (EMPTY_SLIST(n->lsrql)) - { - if (n->state == NEIGHBOR_LOADING) - ospf_neigh_sm(n, INM_LOADDONE); - return; - } + /* ASSERT((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrql)); */ pkt = ospf_tx_buffer(ifa); ospf_pkt_fill_hdr(ifa, pkt, LSREQ_P); ospf_lsreq_body(p, pkt, &lsrs, &lsr_max); - /* We send smaller LSREQ to prevent multiple LSACKs as answer */ - lsr_max = lsr_max / 4; - i = 0; - WALK_SLIST(en, n->lsrql) + WALK_SLIST(req, n->lsrql) { if (i == lsr_max) break; DBG("Requesting %uth LSA: Type: %04u, ID: %R, RT: %R, SN: 0x%x, Age %u\n", - i, en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age); + i, req->lsa_type, req->lsa.id, req->lsa.rt, req->lsa.sn, req->lsa.age); - u32 etype = lsa_get_etype(&en->lsa, p); + u32 etype = lsa_get_etype(&req->lsa, p); lsrs[i].type = htonl(etype); - lsrs[i].rt = htonl(en->lsa.rt); - lsrs[i].id = htonl(en->lsa.id); + lsrs[i].rt = htonl(req->lsa.rt); + lsrs[i].id = htonl(req->lsa.id); i++; } + /* We store the position to see whether requested LSAs have been received */ + n->lsrqi = req; + length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsreq_header); pkt->length = htons(length); diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index 0aa45f6a..ea32923a 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -32,8 +32,8 @@ ospf_dump_lsahdr(struct ospf_proto *p, struct ospf_lsa_header *lsa_n) lsa_ntoh_hdr(lsa_n, &lsa); lsa_etype = lsa_get_etype(&lsa, p); - log(L_TRACE "%s: LSA Type: %04x, Id: %R, Rt: %R, Age: %u, Seq: %08x, Sum: %04x", - p->p.name, lsa_etype, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum); + log(L_TRACE "%s: LSA Type: %04x, Id: %R, Rt: %R, Seq: %08x, Age: %u, Sum: %04x", + p->p.name, lsa_etype, lsa.id, lsa.rt, lsa.sn, lsa.age, lsa.checksum); } void @@ -65,46 +65,64 @@ ospf_lsupd_set_lsa_count(struct ospf_packet *pkt, uint hdrlen, u32 val) static inline void ospf_lsupd_body(struct ospf_proto *p, struct ospf_packet *pkt, - uint *offset, uint *bound, uint *lsa_count) + uint *offset, uint *lsa_count) { uint hlen = ospf_lsupd_hdrlen(p); *offset = hlen; - *bound = ntohs(pkt->length) - sizeof(struct ospf_lsa_header); *lsa_count = ospf_lsupd_get_lsa_count(pkt, hlen); } static void ospf_dump_lsupd(struct ospf_proto *p, struct ospf_packet *pkt) { - uint offset, bound, i, lsa_count, lsalen; + uint offset, plen, i, lsa_count, lsa_len; ASSERT(pkt->type == LSUPD_P); ospf_dump_common(p, pkt); - ospf_lsupd_body(p, pkt, &offset, &bound, &lsa_count); + plen = ntohs(pkt->length); + ospf_lsupd_body(p, pkt, &offset, &lsa_count); for (i = 0; i < lsa_count; i++) { - if (offset > bound) - { - log(L_TRACE "%s: LSA invalid", p->p.name); - return; - } + if ((offset + sizeof(struct ospf_lsa_header)) > plen) + goto invalid; struct ospf_lsa_header *lsa = ((void *) pkt) + offset; - ospf_dump_lsahdr(p, lsa); - lsalen = ntohs(lsa->length); - offset += lsalen; + lsa_len = ntohs(lsa->length); - if (((lsalen % 4) != 0) || (lsalen <= sizeof(struct ospf_lsa_header))) - { - log(L_TRACE "%s: LSA invalid", p->p.name); - return; - } + if (((lsa_len % 4) != 0) || (lsa_len <= sizeof(struct ospf_lsa_header))) + goto invalid; + + ospf_dump_lsahdr(p, lsa); + offset += lsa_len; } + return; + +invalid: + log(L_TRACE "%s: LSA invalid", p->p.name); + return; } static inline void +ospf_lsa_lsrq_down(struct top_hash_entry *req, struct ospf_neighbor *n, struct ospf_neighbor *from) +{ + if (req == n->lsrqi) + n->lsrqi = SNODE_NEXT(req); + + s_rem_node(SNODE req); + ospf_hash_delete(n->lsrqh, req); + + if (EMPTY_SLIST(n->lsrql)) + { + tm_stop(n->lsrq_timer); + + if (n->state == NEIGHBOR_LOADING) + ospf_neigh_sm(n, INM_LOADDONE); + } +} + +static inline void ospf_lsa_lsrt_up(struct top_hash_entry *en, struct ospf_neighbor *n) { struct top_hash_entry *ret = ospf_hash_get_entry(n->lsrth, en); @@ -117,6 +135,22 @@ ospf_lsa_lsrt_up(struct top_hash_entry *en, struct ospf_neighbor *n) ret->lsa = en->lsa; ret->lsa_body = LSA_BODY_DUMMY; + + if (!tm_active(n->lsrt_timer)) + tm_start(n->lsrt_timer, n->ifa->rxmtint); +} + +void +ospf_lsa_lsrt_down_(struct top_hash_entry *en, struct ospf_neighbor *n, struct top_hash_entry *ret) +{ + if (en) + en->ret_count--; + + s_rem_node(SNODE ret); + ospf_hash_delete(n->lsrth, ret); + + if (EMPTY_SLIST(n->lsrtl)) + tm_stop(n->lsrt_timer); } static inline int @@ -125,14 +159,9 @@ ospf_lsa_lsrt_down(struct top_hash_entry *en, struct ospf_neighbor *n) struct top_hash_entry *ret = ospf_hash_find_entry(n->lsrth, en); if (ret) - { - en->ret_count--; - s_rem_node(SNODE ret); - ospf_hash_delete(n->lsrth, ret); - return 1; - } + ospf_lsa_lsrt_down_(en, n, ret); - return 0; + return ret != NULL; } void @@ -144,10 +173,61 @@ ospf_add_flushed_to_lsrt(struct ospf_proto *p, struct ospf_neighbor *n) if ((en->lsa.age == LSA_MAXAGE) && (en->lsa_body != NULL) && lsa_flooding_allowed(en->lsa_type, en->domain, n->ifa)) ospf_lsa_lsrt_up(en, n); + + /* If we found any flushed LSA, we send them ASAP */ + if (tm_active(n->lsrt_timer)) + tm_start(n->lsrt_timer, 0); } +static int ospf_flood_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa_count, uint lsa_min_count, struct ospf_iface *ifa); + +static void +ospf_enqueue_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_iface *ifa) +{ + if (ifa->flood_queue_used == ifa->flood_queue_size) + { + /* If we already have full queue, we send some packets */ + uint sent = ospf_flood_lsupd(p, ifa->flood_queue, ifa->flood_queue_used, ifa->flood_queue_used / 2, ifa); + int i; + + for (i = 0; i < sent; i++) + ifa->flood_queue[i]->ret_count--; -static void ospf_send_lsupd_to_ifa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_iface *ifa); + ifa->flood_queue_used -= sent; + memmove(ifa->flood_queue, ifa->flood_queue + sent, ifa->flood_queue_used * sizeof(void *)); + bzero(ifa->flood_queue + ifa->flood_queue_used, sent * sizeof(void *)); + } + + en->ret_count++; + ifa->flood_queue[ifa->flood_queue_used] = en; + ifa->flood_queue_used++; + + if (!ev_active(p->flood_event)) + ev_schedule(p->flood_event); +} + +void +ospf_flood_event(void *ptr) +{ + struct ospf_proto *p = ptr; + struct ospf_iface *ifa; + int i, count; + + WALK_LIST(ifa, p->iface_list) + { + if (ifa->flood_queue_used == 0) + continue; + + count = ifa->flood_queue_used; + ospf_flood_lsupd(p, ifa->flood_queue, count, count, ifa); + + for (i = 0; i < count; i++) + ifa->flood_queue[i]->ret_count--; + + ifa->flood_queue_used = 0; + bzero(ifa->flood_queue, count * sizeof(void *)); + } +} /** @@ -195,14 +275,7 @@ ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neig /* If same or newer, remove LSA from the link state request list */ if (cmp > CMP_OLDER) - { - s_rem_node(SNODE req); - ospf_hash_delete(n->lsrqh, req); - n->want_lsreq = 1; - - if ((EMPTY_SLIST(n->lsrql)) && (n->state == NEIGHBOR_LOADING)) - ospf_neigh_sm(n, INM_LOADDONE); - } + ospf_lsa_lsrq_down(req, n, from); /* If older or same, skip processing of this neighbor */ if (cmp < CMP_NEWER) @@ -242,7 +315,7 @@ ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neig } /* 13.3 (5) - finally flood the packet */ - ospf_send_lsupd_to_ifa(p, en, ifa); + ospf_enqueue_lsa(p, en, ifa); } return back; @@ -302,26 +375,33 @@ ospf_prepare_lsupd(struct ospf_proto *p, struct ospf_iface *ifa, } -static void -ospf_send_lsupd_to_ifa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_iface *ifa) +static int +ospf_flood_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa_count, uint lsa_min_count, struct ospf_iface *ifa) { - uint c = ospf_prepare_lsupd(p, ifa, &en, 1); + uint i, c; - if (!c) /* Too large LSA */ - return; + for (i = 0; i < lsa_min_count; i += c) + { + c = ospf_prepare_lsupd(p, ifa, lsa_list + i, lsa_count - i); - OSPF_PACKET(ospf_dump_lsupd, ospf_tx_buffer(ifa), - "LSUPD packet flooded via %s", ifa->ifname); + if (!c) /* Too large LSA */ + { i++; continue; } - if (ifa->type == OSPF_IT_BCAST) - { - if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) - ospf_send_to_all(ifa); + OSPF_PACKET(ospf_dump_lsupd, ospf_tx_buffer(ifa), + "LSUPD packet flooded via %s", ifa->ifname); + + if (ifa->type == OSPF_IT_BCAST) + { + if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) + ospf_send_to_all(ifa); + else + ospf_send_to_des(ifa); + } else - ospf_send_to_des(ifa); + ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); } - else - ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); + + return i; } int @@ -343,17 +423,19 @@ ospf_send_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa ospf_send_to(ifa, n->ip); } - return lsa_count; + return i; } void ospf_rxmt_lsupd(struct ospf_proto *p, struct ospf_neighbor *n) { - const uint max = 128; + uint max = 2 * n->ifa->flood_queue_size; struct top_hash_entry *entries[max]; struct top_hash_entry *ret, *nxt, *en; uint i = 0; + /* ASSERT((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrtl)); */ + WALK_SLIST_DELSAFE(ret, nxt, n->lsrtl) { if (i == max) @@ -398,14 +480,15 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_proto *p = ifa->oa->po; const char *err_dsc = NULL; uint plen, err_val = 0; - int skip_lsreq = 0; - n->want_lsreq = 0; /* RFC 2328 13. */ plen = ntohs(pkt->length); - if (plen < (ospf_lsupd_hdrlen(p) + sizeof(struct ospf_lsa_header))) - DROP("too short", plen); + if (plen < ospf_lsupd_hdrlen(p)) + { + LOG_PKT("Bad LSUPD packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", plen); + return; + } OSPF_PACKET(ospf_dump_lsupd, pkt, "LSUPD packet received from nbr %R on %s", n->rid, ifa->ifname); @@ -417,8 +500,8 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, ospf_neigh_sm(n, INM_HELLOREC); /* Questionable */ - uint offset, bound, i, lsa_count; - ospf_lsupd_body(p, pkt, &offset, &bound, &lsa_count); + uint offset, i, lsa_count; + ospf_lsupd_body(p, pkt, &offset, &lsa_count); for (i = 0; i < lsa_count; i++) { @@ -426,7 +509,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, struct top_hash_entry *en; u32 lsa_len, lsa_type, lsa_domain; - if (offset > bound) + if ((offset + sizeof(struct ospf_lsa_header)) > plen) DROP("too short", plen); /* LSA header in network order */ @@ -492,7 +575,6 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, if (en && ((now - en->inst_time) < MINLSARRIVAL)) { OSPF_TRACE(D_EVENTS, "Skipping LSA received in less that MinLSArrival"); - skip_lsreq = 1; continue; } @@ -559,7 +641,9 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, continue; } - /* FIXME pg145 (6) */ + /* 13. (6) - received LSA is in Link state request list (but not newer) */ + if (ospf_hash_find_entry(n->lsrqh, en) != NULL) + DROP1("error in LSA database exchange"); /* 13. (7) - received LSA is same */ if (lsa_comp(&lsa, &en->lsa) == CMP_SAME) @@ -576,7 +660,6 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, else ospf_enqueue_lsack(n, lsa_n, ACKL_DIRECT); - skip_lsreq = 1; continue; } @@ -601,15 +684,24 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, /* Send direct LSACKs */ ospf_send_lsack(p, n, ACKL_DIRECT); + /* Send enqueued LSAs immediately, do not wait for flood_event */ + if (ev_active(p->flood_event)) + { + ev_postpone(p->flood_event); + ospf_flood_event(p); + } + /* - * In loading state, we should ask for another batch of LSAs. This is only - * vaguely mentioned in RFC 2328. We send a new LSREQ only if the current - * LSUPD actually removed some entries from LSA request list (want_lsreq) and - * did not contain duplicate or early LSAs (skip_lsreq). The first condition - * prevents endless floods, the second condition helps with flow control. + * During loading, we should ask for another batch of LSAs. This is only + * vaguely mentioned in RFC 2328. We send a new LSREQ if all requests sent in + * the last packet were already answered and/or removed from the LS request + * list and therefore lsrqi is pointing to the first node of the list. */ - if ((n->state == NEIGHBOR_LOADING) && n->want_lsreq && !skip_lsreq) + if (!EMPTY_SLIST(n->lsrql) && (n->lsrqi == SHEAD(n->lsrql))) + { ospf_send_lsreq(p, n); + tm_start(n->lsrq_timer, n->ifa->rxmtint); + } return; @@ -617,7 +709,7 @@ drop: LOG_PKT("Bad LSUPD packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, err_dsc, err_val); - // XXXX realy? - ospf_neigh_sm(n, INM_SEQMIS); + /* Malformed LSUPD - there is no defined error event, we abuse BadLSReq */ + ospf_neigh_sm(n, INM_BADLSREQ); return; } diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index c75b1b93..c5d44dec 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -23,14 +23,18 @@ const char *ospf_inm_names[] = { static int can_do_adj(struct ospf_neighbor *n); -static void neighbor_timer_hook(timer * timer); -static void rxmt_timer_hook(timer * timer); -static void ackd_timer_hook(timer * t); +static void inactivity_timer_hook(timer * timer); +static void dbdes_timer_hook(timer *t); +static void lsrq_timer_hook(timer *t); +static void lsrt_timer_hook(timer *t); +static void ackd_timer_hook(timer *t); + static void init_lists(struct ospf_proto *p, struct ospf_neighbor *n) { s_init_list(&(n->lsrql)); + n->lsrqi = SHEAD(n->lsrql); n->lsrqh = ospf_top_new(p, n->pool); s_init_list(&(n->lsrtl)); @@ -57,9 +61,16 @@ release_lsrtl(struct ospf_proto *p, struct ospf_neighbor *n) static void reset_lists(struct ospf_proto *p, struct ospf_neighbor *n) { - release_lsrtl(p,n); + release_lsrtl(p, n); ospf_top_free(n->lsrqh); ospf_top_free(n->lsrth); + ospf_reset_lsack_queue(n); + + tm_stop(n->dbdes_timer); + tm_stop(n->lsrq_timer); + tm_stop(n->lsrt_timer); + tm_stop(n->ackd_timer); + init_lists(p, n); } @@ -80,30 +91,14 @@ ospf_neighbor_new(struct ospf_iface *ifa) init_lists(p, n); s_init(&(n->dbsi), &(p->lsal)); - n->inactim = tm_new(pool); - n->inactim->data = n; - n->inactim->randomize = 0; - n->inactim->hook = neighbor_timer_hook; - n->inactim->recurrent = 0; - DBG("%s: Installing inactivity timer.\n", p->p.name); - - n->rxmt_timer = tm_new(pool); - n->rxmt_timer->data = n; - n->rxmt_timer->randomize = 0; - n->rxmt_timer->hook = rxmt_timer_hook; - n->rxmt_timer->recurrent = ifa->rxmtint; - tm_start(n->rxmt_timer, n->ifa->rxmtint); - DBG("%s: Installing rxmt timer.\n", p->p.name); - - n->ackd_timer = tm_new(pool); - n->ackd_timer->data = n; - n->ackd_timer->randomize = 0; - n->ackd_timer->hook = ackd_timer_hook; - n->ackd_timer->recurrent = ifa->rxmtint / 2; init_list(&n->ackl[ACKL_DIRECT]); init_list(&n->ackl[ACKL_DELAY]); - tm_start(n->ackd_timer, n->ifa->rxmtint / 2); - DBG("%s: Installing ackd timer.\n", p->p.name); + + n->inactim = tm_new_set(pool, inactivity_timer_hook, n, 0, 0); + n->dbdes_timer = tm_new_set(pool, dbdes_timer_hook, n, 0, ifa->rxmtint); + n->lsrq_timer = tm_new_set(pool, lsrq_timer_hook, n, 0, ifa->rxmtint); + n->lsrt_timer = tm_new_set(pool, lsrt_timer_hook, n, 0, ifa->rxmtint); + n->ackd_timer = tm_new_set(pool, ackd_timer_hook, n, 0, ifa->rxmtint / 2); return (n); } @@ -188,6 +183,9 @@ ospf_neigh_chstate(struct ospf_neighbor *n, u8 state) n->dds++; n->myimms = DBDES_IMMS; + + tm_start(n->dbdes_timer, 0); + tm_start(n->ackd_timer, ifa->rxmtint / 2); } if (state > NEIGHBOR_EXSTART) @@ -253,16 +251,16 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) /* Add MaxAge LSA entries to retransmission list */ ospf_add_flushed_to_lsrt(p, n); - - /* FIXME: Why is this here ? */ - ospf_reset_lsack_queue(n); } else bug("NEGDONE and I'm not in EXSTART?"); break; case INM_EXDONE: - ospf_neigh_chstate(n, NEIGHBOR_LOADING); + if (!EMPTY_SLIST(n->lsrql)) + ospf_neigh_chstate(n, NEIGHBOR_LOADING); + else + ospf_neigh_chstate(n, NEIGHBOR_FULL); break; case INM_LOADDONE: @@ -270,23 +268,15 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) break; case INM_ADJOK: - switch (n->state) + /* Can In build adjacency? */ + if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n)) { - case NEIGHBOR_2WAY: - /* Can In build adjacency? */ - if (can_do_adj(n)) - { - ospf_neigh_chstate(n, NEIGHBOR_EXSTART); - } - break; - default: - if (n->state >= NEIGHBOR_EXSTART) - if (!can_do_adj(n)) - { - reset_lists(p, n); - ospf_neigh_chstate(n, NEIGHBOR_2WAY); - } - break; + ospf_neigh_chstate(n, NEIGHBOR_EXSTART); + } + else if ((n->state >= NEIGHBOR_EXSTART) && !can_do_adj(n)) + { + reset_lists(p, n); + ospf_neigh_chstate(n, NEIGHBOR_2WAY); } break; @@ -566,12 +556,12 @@ find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip) } static void -neighbor_timer_hook(timer * timer) +inactivity_timer_hook(timer * timer) { struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data; struct ospf_proto *p = n->ifa->oa->po; - OSPF_TRACE(D_EVENTS, "Inactivity timer expired for neighbor %R on %s", + OSPF_TRACE(D_EVENTS, "Inactivity timer expired for nbr %R on %s", n->rid, n->ifa->ifname); ospf_neigh_sm(n, INM_INACTTIM); } @@ -584,7 +574,7 @@ ospf_neigh_bfd_hook(struct bfd_request *req) if (req->down) { - OSPF_TRACE(D_EVENTS, "BFD session down for neighbor %R on %s", + OSPF_TRACE(D_EVENTS, "BFD session down for nbr %R on %s", n->rid, n->ifa->ifname); ospf_neigh_sm(n, INM_INACTTIM); } @@ -605,11 +595,60 @@ ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd) } +static void +dbdes_timer_hook(timer *t) +{ + struct ospf_neighbor *n = t->data; + struct ospf_proto *p = n->ifa->oa->po; + + // OSPF_TRACE(D_EVENTS, "DBDES timer expired for nbr %R on %s", n->rid, n->ifa->ifname); + + if (n->state == NEIGHBOR_EXSTART) + ospf_send_dbdes(p, n); + + if ((n->state == NEIGHBOR_EXCHANGE) && (n->myimms & DBDES_MS)) + ospf_rxmt_dbdes(p, n); +} + +static void +lsrq_timer_hook(timer *t) +{ + struct ospf_neighbor *n = t->data; + struct ospf_proto *p = n->ifa->oa->po; + + // OSPF_TRACE(D_EVENTS, "LSRQ timer expired for nbr %R on %s", n->rid, n->ifa->ifname); + + if ((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrql)) + ospf_send_lsreq(p, n); +} + +static void +lsrt_timer_hook(timer *t) +{ + struct ospf_neighbor *n = t->data; + struct ospf_proto *p = n->ifa->oa->po; + + // OSPF_TRACE(D_EVENTS, "LSRT timer expired for nbr %R on %s", n->rid, n->ifa->ifname); + + if ((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrtl)) + ospf_rxmt_lsupd(p, n); +} + +static void +ackd_timer_hook(timer *t) +{ + struct ospf_neighbor *n = t->data; + struct ospf_proto *p = n->ifa->oa->po; + + ospf_send_lsack(p, n, ACKL_DELAY); +} + + void ospf_sh_neigh_info(struct ospf_neighbor *n) { struct ospf_iface *ifa = n->ifa; - char *pos = "ptp "; + char *pos = "PtP "; char etime[6]; int exp, sec, min; @@ -628,55 +667,13 @@ ospf_sh_neigh_info(struct ospf_neighbor *n) if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA)) { if (n->rid == ifa->drid) - pos = "dr "; + pos = "DR "; else if (n->rid == ifa->bdrid) - pos = "bdr "; + pos = "BDR "; else - pos = "other"; + pos = "Other"; } cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority, ospf_ns_names[n->state], pos, etime, ifa->ifname, n->ip); } - -static void -rxmt_timer_hook(timer *t) -{ - struct ospf_neighbor *n = t->data; - struct ospf_proto *p = n->ifa->oa->po; - - DBG("%s: RXMT timer fired on %s for neigh %I\n", - p->p.name, n->ifa->ifname, n->ip); - - switch (n->state) - { - case NEIGHBOR_EXSTART: - ospf_send_dbdes(p, n); - return; - - case NEIGHBOR_EXCHANGE: - if (n->myimms & DBDES_MS) - ospf_rxmt_dbdes(p, n); - case NEIGHBOR_LOADING: - ospf_send_lsreq(p, n); - return; - - case NEIGHBOR_FULL: - /* LSA retransmissions */ - if (!EMPTY_SLIST(n->lsrtl)) - ospf_rxmt_lsupd(p, n); - return; - } -} - -static void -ackd_timer_hook(timer *t) -{ - struct ospf_neighbor *n = t->data; - struct ospf_proto *p = n->ifa->oa->po; - - DBG("%s: ACKD timer fired on %s for neigh %I\n", - p->p.name, n->ifa->ifname, n->ip); - - ospf_send_lsack(p, n, ACKL_DELAY); -} diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index 01e53922..dab7aab8 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -235,11 +235,7 @@ ospf_start(struct proto *P) p->asbr = c->asbr; p->ecmp = c->ecmp; p->tick = c->tick; - p->disp_timer = tm_new(P->pool); - p->disp_timer->data = p; - p->disp_timer->randomize = 0; - p->disp_timer->hook = ospf_disp; - p->disp_timer->recurrent = p->tick; + p->disp_timer = tm_new_set(P->pool, ospf_disp, p, 0, p->tick); tm_start(p->disp_timer, 1); p->lsab_size = 256; p->lsab_used = 0; @@ -252,6 +248,10 @@ ospf_start(struct proto *P) p->gr = ospf_top_new(p, P->pool); s_init_list(&(p->lsal)); + p->flood_event = ev_new(P->pool); + p->flood_event->hook = ospf_flood_event; + p->flood_event->data = p; + p->log_pkt_tbf = (struct tbf){ .rate = 1, .burst = 5 }; p->log_lsa_tbf = (struct tbf){ .rate = 4, .burst = 20 }; @@ -1439,14 +1439,14 @@ ospf_sh_lsadb(struct lsadb_show_data *ld) break; } cli_msg(-1017, ""); - cli_msg(-1017," Type LS ID Router Age Sequence Checksum"); + cli_msg(-1017," Type LS ID Router Sequence Age Checksum"); last_dscope = dscope; last_domain = hea[i]->domain; } - cli_msg(-1017," %04x %-15R %-15R %5u %08x %04x", - lsa_type, lsa->id, lsa->rt, lsa->age, lsa->sn, lsa->checksum); + cli_msg(-1017," %04x %-15R %-15R %08x %5u %04x", + lsa_type, lsa->id, lsa->rt, lsa->sn, lsa->age, lsa->checksum); } cli_msg(0, ""); } diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index e535287c..c324f431 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -231,6 +231,7 @@ struct ospf_proto byte asbr; /* May i originate any ext/NSSA lsa? */ byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */ struct ospf_area *backbone; /* If exists */ + event *flood_event; /* Event for flooding LS updates */ void *lsab; /* LSA buffer used when originating router LSAs */ int lsab_size, lsab_used; linpool *nhpool; /* Linpool used for next hops computed in SPF */ @@ -317,8 +318,11 @@ struct ospf_iface struct top_hash_entry *link_lsa; /* Originated link LSA */ struct top_hash_entry *net_lsa; /* Originated network LSA */ struct top_hash_entry *pxn_lsa; /* Originated prefix LSA */ + struct top_hash_entry **flood_queue; /* LSAs queued for LSUPD */ u8 update_link_lsa; u8 update_net_lsa; + u16 flood_queue_used; /* The current number of LSAs in flood_queue */ + u16 flood_queue_size; /* The maximum number of LSAs in flood_queue */ int fadj; /* Number of fully adjacent neighbors */ list nbma_list; u8 priority; /* A router priority for DR election */ @@ -354,7 +358,6 @@ struct ospf_neighbor ip_addr ip; /* IP of it's interface */ u8 priority; /* Priority */ u8 adj; /* built adjacency? */ - u8 want_lsreq; /* Set to 1 when lsrql was shortened during LSUPD */ u32 options; /* Options received */ /* Entries dr and bdr store IP addresses in OSPFv2 and router IDs in @@ -373,6 +376,7 @@ struct ospf_neighbor */ slist lsrql; /* slist of struct top_hash_entry from n->lsrqh */ struct top_graph *lsrqh; + struct top_hash_entry *lsrqi; /* Pointer to the first unsent node in lsrql */ /* Link state retransmission list, controls LSA retransmission during flood. * Entries added as sent in lsupd packets, removed when received in lsack packets. @@ -380,7 +384,9 @@ struct ospf_neighbor */ slist lsrtl; /* slist of struct top_hash_entry from n->lsrth */ struct top_graph *lsrth; - timer *rxmt_timer; /* RXMT timer */ + timer *dbdes_timer; /* DBDES exchange timer */ + timer *lsrq_timer; /* LSA request timer */ + timer *lsrt_timer; /* LSA retransmission timer */ list ackl[2]; #define ACKL_DIRECT 0 #define ACKL_DELAY 1 @@ -940,7 +946,9 @@ void ospf_receive_lsreq(struct ospf_packet *pkt, struct ospf_iface *ifa, struct /* lsupd.c */ void ospf_dump_lsahdr(struct ospf_proto *p, struct ospf_lsa_header *lsa_n); void ospf_dump_common(struct ospf_proto *p, struct ospf_packet *pkt); +void ospf_lsa_lsrt_down_(struct top_hash_entry *en, struct ospf_neighbor *n, struct top_hash_entry *ret); void ospf_add_flushed_to_lsrt(struct ospf_proto *p, struct ospf_neighbor *n); +void ospf_flood_event(void *ptr); int ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neighbor *from); int ospf_send_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa_count, struct ospf_neighbor *n); void ospf_rxmt_lsupd(struct ospf_proto *p, struct ospf_neighbor *n); diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index a545c7fd..fb63e61c 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -260,7 +260,7 @@ ospf_rx_hook(sock *sk, int len) * link-local src address, but does not enforce it. Strange. */ if (dst_mcast && !src_local) - LOG_PKT_WARN("Multicast packet received from not-link-local %I via %s", + LOG_PKT_WARN("Multicast packet received from non-link-local %I via %s", sk->faddr, ifa->ifname); } @@ -396,8 +396,7 @@ found: if (!n && (pkt->type != HELLO_P)) { - // XXXX format - OSPF_TRACE(D_PACKETS, "Non-HELLO packet received from unknown neighbor %R on %s (%I)", + OSPF_TRACE(D_PACKETS, "Non-HELLO packet received from unknown nbr %R on %s, src %I", rid, ifa->ifname, sk->faddr); return 1; } diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 42bf9c45..c21c23d5 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -404,9 +404,6 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en) void ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en) { - OSPF_TRACE(D_EVENTS, "Flushing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", - en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn); - if (en->next_lsa_body) { mb_free(en->next_lsa_body); @@ -418,6 +415,9 @@ ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en) if (en->lsa.age == LSA_MAXAGE) return; + OSPF_TRACE(D_EVENTS, "Flushing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", + en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn); + en->lsa.age = LSA_MAXAGE; ospf_flood_lsa(p, en, NULL); @@ -433,8 +433,12 @@ ospf_clear_lsa(struct ospf_proto *p, struct top_hash_entry *en) /* * Called by ospf_update_lsadb() as part of LSA flushing process. * Flushed LSA was acknowledged by neighbors and we can free its content. + * The log message is for 'remove' - we hide empty LSAs from users. */ + OSPF_TRACE(D_EVENTS, "Removing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", + en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn); + if (en->lsa.sn == LSA_MAXSEQNO) en->lsa.sn = LSA_ZEROSEQNO; @@ -1143,6 +1147,9 @@ ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 m ospf_originate_lsa(p, &lsa); } +static struct top_hash_entry * +ospf_hash_find_(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type); + static void ospf_flush_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf) { @@ -1152,7 +1159,7 @@ ospf_flush_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf) u32 dom = oa ? oa->areaid : 0; u32 id = ort_to_lsaid(p, nf); - en = ospf_hash_find(p->gr, dom, id, p->router_id, type); + en = ospf_hash_find_(p->gr, dom, id, p->router_id, type); if (!en || (en->nf != nf)) return; @@ -1795,8 +1802,8 @@ ospf_top_rehash(struct top_graph *f, int step) ospf_top_ht_free(oldt); } -struct top_hash_entry * -ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) +static struct top_hash_entry * +ospf_hash_find_(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) { struct top_hash_entry *e; e = f->hash_table[ospf_top_hash(f, domain, lsa, rtr, type)]; @@ -1805,6 +1812,14 @@ ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) e->lsa_type != type || e->domain != domain)) e = e->next; + return e; +} + +struct top_hash_entry * +ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type) +{ + struct top_hash_entry *e = ospf_hash_find_(f, domain, lsa, rtr, type); + /* Hide hash entry with empty lsa_body */ return (e && e->lsa_body) ? e : NULL; } |