diff options
Diffstat (limited to 'ospf6d/ospf6_message.c')
| -rw-r--r-- | ospf6d/ospf6_message.c | 180 |
1 files changed, 137 insertions, 43 deletions
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 14b02dac79..d13799c0e8 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -268,6 +268,18 @@ static struct ospf6_packet *ospf6_packet_new(size_t size) return new; } +static struct ospf6_packet *ospf6_packet_dup(struct ospf6_packet *old) +{ + struct ospf6_packet *new; + + new = XCALLOC(MTYPE_OSPF6_PACKET, sizeof(struct ospf6_packet)); + new->s = stream_dup(old->s); + new->dst = old->dst; + new->length = old->length; + + return new; +} + static void ospf6_packet_free(struct ospf6_packet *op) { if (op->s) @@ -407,6 +419,25 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, hello = (struct ospf6_hello *)((caddr_t)oh + sizeof(struct ospf6_header)); + if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT + || oi->state == OSPF6_INTERFACE_POINTTOMULTIPOINT) + && oi->p2xp_only_cfg_neigh) { + /* NEVER, never, ever, do this on broadcast (or NBMA)! + * DR/BDR election requires everyone to talk to everyone else + * only for PtP/PtMP we can be selective in adjacencies! + */ + struct ospf6_if_p2xp_neighcfg *p2xp_cfg; + + p2xp_cfg = ospf6_if_p2xp_find(oi, src); + if (!p2xp_cfg) { + if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR)) + zlog_debug( + "ignoring PtP/PtMP hello from %pI6, neighbor not configured", + src); + return; + } + } + /* HelloInterval check */ if (ntohs(hello->hello_interval) != oi->hello_interval) { zlog_warn( @@ -479,7 +510,7 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, on->hello_in++; /* Always override neighbor's source address */ - memcpy(&on->linklocal_addr, src, sizeof(struct in6_addr)); + ospf6_neighbor_lladdr_set(on, src); /* Neighbor ifindex check */ if (on->ifindex != (ifindex_t)ntohl(hello->interface_id)) { @@ -535,9 +566,9 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, oi->hello_in++; /* Execute neighbor events */ - event_execute(master, hello_received, on, 0); + event_execute(master, hello_received, on, 0, NULL); if (twoway) - event_execute(master, twoway_received, on, 0); + event_execute(master, twoway_received, on, 0, NULL); else { if (OSPF6_GR_IS_ACTIVE_HELPER(on)) { if (IS_DEBUG_OSPF6_GR) @@ -553,7 +584,7 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, * receives one_way hellow when it acts as HELPER for * that specific neighbor. */ - event_execute(master, oneway_received, on, 0); + event_execute(master, oneway_received, on, 0, NULL); } } @@ -624,15 +655,15 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh, return; case OSPF6_NEIGHBOR_INIT: - event_execute(master, twoway_received, on, 0); + event_execute(master, twoway_received, on, 0, NULL); if (on->state != OSPF6_NEIGHBOR_EXSTART) { if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR)) zlog_debug( "Neighbor state is not ExStart, ignore"); return; } - /* else fall through to ExStart */ - /* fallthru */ + /* else fall through to ExStart */ + fallthrough; case OSPF6_NEIGHBOR_EXSTART: /* if neighbor obeys us as our slave, schedule negotiation_done and process LSA Headers. Otherwise, ignore this message */ @@ -640,7 +671,7 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh, && !CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT) && ntohl(dbdesc->seqnum) == on->dbdesc_seqnum) { /* execute NegotiationDone */ - event_execute(master, negotiation_done, on, 0); + event_execute(master, negotiation_done, on, 0, NULL); /* Record neighbor options */ memcpy(on->options, dbdesc->options, @@ -650,8 +681,8 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh, on->ospf6_if->interface->vrf->name, on->name); return; } - /* fall through to exchange */ - + /* fall through to exchange */ + fallthrough; case OSPF6_NEIGHBOR_EXCHANGE: if (!memcmp(dbdesc, &on->dbdesc_last, sizeof(struct ospf6_dbdesc))) { @@ -828,15 +859,15 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh, return; case OSPF6_NEIGHBOR_INIT: - event_execute(master, twoway_received, on, 0); + event_execute(master, twoway_received, on, 0, NULL); if (on->state != OSPF6_NEIGHBOR_EXSTART) { if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR)) zlog_debug( "Neighbor state is not ExStart, ignore"); return; } - /* else fall through to ExStart */ - /* fallthru */ + /* else fall through to ExStart */ + fallthrough; case OSPF6_NEIGHBOR_EXSTART: /* If the neighbor is Master, act as Slave. Schedule negotiation_done @@ -855,7 +886,7 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh, on->dbdesc_seqnum = ntohl(dbdesc->seqnum); /* schedule NegotiationDone */ - event_execute(master, negotiation_done, on, 0); + event_execute(master, negotiation_done, on, 0, NULL); /* Record neighbor options */ memcpy(on->options, dbdesc->options, @@ -2239,11 +2270,24 @@ static void ospf6_write(struct event *thread) void ospf6_hello_send(struct event *thread) { struct ospf6_interface *oi; - struct ospf6_packet *op; - uint16_t length = OSPF6_HEADER_SIZE; oi = (struct ospf6_interface *)EVENT_ARG(thread); + /* Check if the GR hello-delay is active. */ + if (oi->gr.hello_delay.t_grace_send) + return; + + /* Check if config is still being processed */ + if (event_is_scheduled(t_ospf6_cfg)) { + if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO, SEND)) + zlog_debug( + "Suppressing Hello on interface %s during config load", + oi->interface->name); + event_add_timer(master, ospf6_hello_send, oi, + oi->hello_interval, &oi->thread_send_hello); + return; + } + if (oi->state <= OSPF6_INTERFACE_DOWN) { if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO, SEND_HDR)) zlog_debug("Unable to send Hello on down interface %s", @@ -2251,6 +2295,20 @@ void ospf6_hello_send(struct event *thread) return; } + event_add_timer(master, ospf6_hello_send, oi, oi->hello_interval, + &oi->thread_send_hello); + + ospf6_hello_send_addr(oi, NULL); +} + +/* used to send polls for PtP/PtMP too */ +void ospf6_hello_send_addr(struct ospf6_interface *oi, + const struct in6_addr *addr) +{ + struct ospf6_packet *op; + uint16_t length = OSPF6_HEADER_SIZE; + bool anything = false; + op = ospf6_packet_new(oi->ifmtu); ospf6_make_header(OSPF6_MESSAGE_TYPE_HELLO, oi, op->s); @@ -2269,20 +2327,40 @@ void ospf6_hello_send(struct event *thread) /* Set packet length. */ op->length = length; - op->dst = allspfrouters6; - - ospf6_fill_hdr_checksum(oi, op); + if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT + || oi->state == OSPF6_INTERFACE_POINTTOMULTIPOINT) + && !addr && oi->p2xp_no_multicast_hello) { + struct listnode *node; + struct ospf6_neighbor *on; + struct ospf6_packet *opdup; + + for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, on)) { + if (on->state < OSPF6_NEIGHBOR_INIT) + /* poll-interval for these */ + continue; + + opdup = ospf6_packet_dup(op); + opdup->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(oi, opdup); + ospf6_packet_add_top(oi, opdup); + anything = true; + } - /* Add packet to the top of the interface output queue, so that they - * can't get delayed by things like long queues of LS Update packets - */ - ospf6_packet_add_top(oi, op); + ospf6_packet_free(op); + } else { + op->dst = addr ? *addr : allspfrouters6; - /* set next thread */ - event_add_timer(master, ospf6_hello_send, oi, oi->hello_interval, - &oi->thread_send_hello); + /* Add packet to the top of the interface output queue, so that + * they can't get delayed by things like long queues of LS + * Update packets + */ + ospf6_fill_hdr_checksum(oi, op); + ospf6_packet_add_top(oi, op); + anything = true; + } - OSPF6_MESSAGE_WRITE_ON(oi); + if (anything) + OSPF6_MESSAGE_WRITE_ON(oi); } static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s) @@ -2320,9 +2398,9 @@ static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s) if ((length + sizeof(struct ospf6_lsa_header) + OSPF6_HEADER_SIZE) > ospf6_packet_max(on->ospf6_if)) { - ospf6_lsa_unlock(lsa); + ospf6_lsa_unlock(&lsa); if (lsanext) - ospf6_lsa_unlock(lsanext); + ospf6_lsa_unlock(&lsanext); break; } stream_put(s, lsa->header, @@ -2400,9 +2478,9 @@ void ospf6_dbdesc_send_newone(struct event *thread) if (size + sizeof(struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { - ospf6_lsa_unlock(lsa); + ospf6_lsa_unlock(&lsa); if (lsanext) - ospf6_lsa_unlock(lsanext); + ospf6_lsa_unlock(&lsanext); break; } @@ -2421,7 +2499,7 @@ void ospf6_dbdesc_send_newone(struct event *thread) event_add_event(master, exchange_done, on, 0, &on->thread_exchange_done); - event_execute(master, ospf6_dbdesc_send, on, 0); + event_execute(master, ospf6_dbdesc_send, on, 0, NULL); } static uint16_t ospf6_make_lsreq(struct ospf6_neighbor *on, struct stream *s) @@ -2432,9 +2510,9 @@ static uint16_t ospf6_make_lsreq(struct ospf6_neighbor *on, struct stream *s) for (ALL_LSDB(on->request_list, lsa, lsanext)) { if ((length + OSPF6_HEADER_SIZE) > ospf6_packet_max(on->ospf6_if)) { - ospf6_lsa_unlock(lsa); + ospf6_lsa_unlock(&lsa); if (lsanext) - ospf6_lsa_unlock(lsanext); + ospf6_lsa_unlock(&lsanext); break; } stream_putw(s, 0); /* reserved */ @@ -2447,7 +2525,7 @@ static uint16_t ospf6_make_lsreq(struct ospf6_neighbor *on, struct stream *s) if (last_req != NULL) { if (on->last_ls_req != NULL) - on->last_ls_req = ospf6_lsa_unlock(on->last_ls_req); + ospf6_lsa_unlock(&on->last_ls_req); ospf6_lsa_lock(last_req); on->last_ls_req = last_req; @@ -2518,7 +2596,8 @@ void ospf6_lsreq_send(struct event *thread) /* schedule loading_done if request list is empty */ if (on->request_list->count == 0) { - event_add_event(master, loading_done, on, 0, NULL); + event_add_event(master, loading_done, on, 0, + &on->event_loading_done); return; } @@ -2561,9 +2640,7 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on, struct ospf6_interface *oi, struct ospf6_packet *op) { - if (on) { - if ((on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) || (on->ospf6_if->state == OSPF6_INTERFACE_DR) || (on->ospf6_if->state == OSPF6_INTERFACE_BDR)) @@ -2580,6 +2657,8 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on, op->dst = alldrouters6; } if (oi) { + struct ospf6 *ospf6; + ospf6_fill_hdr_checksum(oi, op); ospf6_packet_add(oi, op); /* If ospf instance is being deleted, send the packet @@ -2587,12 +2666,27 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on, */ if ((oi->area == NULL) || (oi->area->ospf6 == NULL)) return; - if (oi->area->ospf6->inst_shutdown) { + + ospf6 = oi->area->ospf6; + if (ospf6->inst_shutdown) { if (oi->on_write_q == 0) { - listnode_add(oi->area->ospf6->oi_write_q, oi); + listnode_add(ospf6->oi_write_q, oi); oi->on_write_q = 1; } - event_execute(master, ospf6_write, oi->area->ospf6, 0); + /* + * When ospf6d immediately calls event_execute + * for items in the oi_write_q. The event_execute + * will call ospf6_write and cause the oi_write_q + * to be emptied. *IF* there is already an event + * scheduled for the oi_write_q by something else + * then when it wakes up in the future and attempts + * to cycle through items in the queue it will + * assert. Let's stop the t_write event and + * if ospf6_write doesn't finish up the work + * it will schedule itself again. + */ + event_cancel(&ospf6->t_write); + event_execute(master, ospf6_write, ospf6, 0, NULL); } else OSPF6_MESSAGE_WRITE_ON(oi); } @@ -2913,9 +3007,9 @@ static uint16_t ospf6_make_lsack_interface(struct ospf6_interface *oi, event_add_event(master, ospf6_lsack_send_interface, oi, 0, &oi->thread_send_lsack); - ospf6_lsa_unlock(lsa); + ospf6_lsa_unlock(&lsa); if (lsanext) - ospf6_lsa_unlock(lsanext); + ospf6_lsa_unlock(&lsanext); break; } ospf6_lsa_age_update_to_send(lsa, oi->transdelay); |
