summaryrefslogtreecommitdiff
path: root/ospf6d/ospf6_message.c
diff options
context:
space:
mode:
Diffstat (limited to 'ospf6d/ospf6_message.c')
-rw-r--r--ospf6d/ospf6_message.c180
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);