#include <netinet/ip6.h>
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_MESSAGE, "OSPF6 message");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PACKET, "OSPF6 packet");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_FIFO, "OSPF6 FIFO queue");
unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0};
static const struct message ospf6_message_type_str[] = {
}
}
+static struct ospf6_packet *ospf6_packet_new(size_t size)
+{
+ struct ospf6_packet *new;
+
+ new = XCALLOC(MTYPE_OSPF6_PACKET, sizeof(struct ospf6_packet));
+ new->s = stream_new(size);
+
+ return new;
+}
+
+static void ospf6_packet_free(struct ospf6_packet *op)
+{
+ if (op->s)
+ stream_free(op->s);
+
+ XFREE(MTYPE_OSPF6_PACKET, op);
+}
+
+struct ospf6_fifo *ospf6_fifo_new(void)
+{
+ struct ospf6_fifo *new;
+
+ new = XCALLOC(MTYPE_OSPF6_FIFO, sizeof(struct ospf6_fifo));
+ return new;
+}
+
+/* Add new packet to fifo. */
+static void ospf6_fifo_push(struct ospf6_fifo *fifo, struct ospf6_packet *op)
+{
+ if (fifo->tail)
+ fifo->tail->next = op;
+ else
+ fifo->head = op;
+
+ fifo->tail = op;
+
+ fifo->count++;
+}
+
+/* Add new packet to head of fifo. */
+static void ospf6_fifo_push_head(struct ospf6_fifo *fifo,
+ struct ospf6_packet *op)
+{
+ op->next = fifo->head;
+
+ if (fifo->tail == NULL)
+ fifo->tail = op;
+
+ fifo->head = op;
+
+ fifo->count++;
+}
+
+/* Delete first packet from fifo. */
+static struct ospf6_packet *ospf6_fifo_pop(struct ospf6_fifo *fifo)
+{
+ struct ospf6_packet *op;
+
+ op = fifo->head;
+
+ if (op) {
+ fifo->head = op->next;
+
+ if (fifo->head == NULL)
+ fifo->tail = NULL;
+
+ fifo->count--;
+ }
+
+ return op;
+}
+
+/* Return first fifo entry. */
+static struct ospf6_packet *ospf6_fifo_head(struct ospf6_fifo *fifo)
+{
+ return fifo->head;
+}
+
+/* Flush ospf packet fifo. */
+void ospf6_fifo_flush(struct ospf6_fifo *fifo)
+{
+ struct ospf6_packet *op;
+ struct ospf6_packet *next;
+
+ for (op = fifo->head; op; op = next) {
+ next = op->next;
+ ospf6_packet_free(op);
+ }
+ fifo->head = fifo->tail = NULL;
+ fifo->count = 0;
+}
+
+/* Free ospf packet fifo. */
+void ospf6_fifo_free(struct ospf6_fifo *fifo)
+{
+ ospf6_fifo_flush(fifo);
+
+ XFREE(MTYPE_OSPF6_FIFO, fifo);
+}
+
+static void ospf6_packet_add(struct ospf6_interface *oi,
+ struct ospf6_packet *op)
+{
+ /* Add packet to end of queue. */
+ ospf6_fifo_push(oi->obuf, op);
+
+ /* Debug of packet fifo*/
+ /* ospf_fifo_debug (oi->obuf); */
+}
+
+static void ospf6_packet_add_top(struct ospf6_interface *oi,
+ struct ospf6_packet *op)
+{
+ /* Add packet to head of queue. */
+ ospf6_fifo_push_head(oi->obuf, op);
+
+ /* Debug of packet fifo*/
+ /* ospf_fifo_debug (oi->obuf); */
+}
+
+static void ospf6_packet_delete(struct ospf6_interface *oi)
+{
+ struct ospf6_packet *op;
+
+ op = ospf6_fifo_pop(oi->obuf);
+
+ if (op)
+ ospf6_packet_free(op);
+}
+
+
static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
struct ospf6_interface *oi,
struct ospf6_header *oh)
int neighborchange = 0;
int neighbor_ifindex_change = 0;
int backupseen = 0;
+ int64_t latency = 0;
+ struct timeval timestamp;
+ monotime(×tamp);
hello = (struct ospf6_hello *)((caddr_t)oh
+ sizeof(struct ospf6_header));
on->priority = hello->priority;
}
+ /* check latency against hello period */
+ if (on->hello_in)
+ latency = monotime_since(&on->last_hello, NULL)
+ - ((int64_t)oi->hello_interval * 1000000);
+ /* log if latency exceeds the hello period */
+ if (latency > ((int64_t)oi->hello_interval * 1000000))
+ zlog_warn("%s RX %pI4 high latency %" PRId64 "us.", __func__,
+ &on->router_id, latency);
+ on->last_hello = timestamp;
+ on->hello_in++;
+
/* Always override neighbor's source address */
memcpy(&on->linklocal_addr, src, sizeof(struct in6_addr));
}
if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Master/Slave bit mismatch");
+ zlog_warn(
+ "DbDesc recv: Master/Slave bit mismatch Nbr %s",
+ on->name);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
}
if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Initialize bit mismatch");
+ zlog_warn("DbDesc recv: Initialize bit mismatch Nbr %s",
+ on->name);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
}
if (memcmp(on->options, dbdesc->options, sizeof(on->options))) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Option field mismatch");
+ zlog_warn("DbDesc recv: Option field mismatch Nbr %s",
+ on->name);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
}
if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug(
- "Sequence number mismatch (%#lx expected)",
- (unsigned long)on->dbdesc_seqnum);
+ zlog_warn(
+ "DbDesc recv: Sequence number mismatch Nbr %s (%#lx expected)",
+ on->name, (unsigned long)on->dbdesc_seqnum);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
return;
}
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Not duplicate dbdesc in state %s",
- ospf6_neighbor_state_str[on->state]);
+ zlog_warn(
+ "DbDesc recv: Not duplicate dbdesc in state %s Nbr %s",
+ ospf6_neighbor_state_str[on->state], on->name);
thread_add_event(master, seqnumber_mismatch, on, 0, NULL);
return;
}
if (ntohs(his->header->type) == OSPF6_LSTYPE_AS_EXTERNAL
- && IS_AREA_STUB(on->ospf6_if->area)) {
+ && (IS_AREA_STUB(on->ospf6_if->area)
+ || IS_AREA_NSSA(on->ospf6_if->area))) {
if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
zlog_debug(
"SeqNumMismatch (E-bit mismatch), discard");
}
if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Master/Slave bit mismatch");
+ zlog_warn(
+ "DbDesc slave recv: Master/Slave bit mismatch Nbr %s",
+ on->name);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
}
if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Initialize bit mismatch");
+ zlog_warn(
+ "DbDesc slave recv: Initialize bit mismatch Nbr %s",
+ on->name);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
}
if (memcmp(on->options, dbdesc->options, sizeof(on->options))) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Option field mismatch");
+ zlog_warn(
+ "DbDesc slave recv: Option field mismatch Nbr %s",
+ on->name);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
}
if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum + 1) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug(
- "Sequence number mismatch (%#lx expected)",
- (unsigned long)on->dbdesc_seqnum + 1);
+ zlog_warn(
+ "DbDesc slave recv: Sequence number mismatch Nbr %s (%#lx expected)",
+ on->name, (unsigned long)on->dbdesc_seqnum + 1);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
return;
}
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Not duplicate dbdesc in state %s",
- ospf6_neighbor_state_str[on->state]);
+ zlog_warn(
+ "DbDesc slave recv: Not duplicate dbdesc in state %s Nbr %s",
+ ospf6_neighbor_state_str[on->state], on->name);
thread_add_event(master, seqnumber_mismatch, on, 0, NULL);
return;
}
if (OSPF6_LSA_SCOPE(his->header->type) == OSPF6_SCOPE_AS
- && IS_AREA_STUB(on->ospf6_if->area)) {
+ && (IS_AREA_STUB(on->ospf6_if->area)
+ || IS_AREA_NSSA(on->ospf6_if->area))) {
if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
zlog_debug("E-bit mismatch with LSA Headers");
ospf6_lsa_delete(his);
/* Find database copy */
lsa = ospf6_lsdb_lookup(e->type, e->id, e->adv_router, lsdb);
if (lsa == NULL) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)) {
- zlog_debug(
- "Can't find requested [%s Id:%pI4 Adv:%pI4]",
- ospf6_lstype_name(e->type), &e->id,
- &e->adv_router);
- }
+ zlog_warn(
+ "Can't find requested lsa [%s Id:%pI4 Adv:%pI4] send badLSReq",
+ ospf6_lstype_name(e->type), &e->id,
+ &e->adv_router);
thread_add_event(master, bad_lsreq, on, 0, NULL);
return;
}
while (length) {
if (length < OSPF6_PREFIX_MIN_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized IPv6 prefix header",
- __func__);
+ zlog_warn("%s: undersized IPv6 prefix header",
+ __func__);
return MSG_NG;
}
/* safe to look deeper */
if (current->prefix_length > IPV6_MAX_BITLEN) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: invalid PrefixLength (%u bits)",
- __func__, current->prefix_length);
+ zlog_warn("%s: invalid PrefixLength (%u bits)",
+ __func__, current->prefix_length);
return MSG_NG;
}
/* covers both fixed- and variable-sized fields */
OSPF6_PREFIX_MIN_SIZE
+ OSPF6_PREFIX_SPACE(current->prefix_length);
if (requested_pfx_bytes > length) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized IPv6 prefix",
- __func__);
+ zlog_warn("%s: undersized IPv6 prefix", __func__);
return MSG_NG;
}
/* next prefix */
real_num_pfxs++;
}
if (real_num_pfxs != req_num_pfxs) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: IPv6 prefix number mismatch (%u required, %u real)",
- __func__, req_num_pfxs, real_num_pfxs);
+ zlog_warn(
+ "%s: IPv6 prefix number mismatch (%u required, %u real)",
+ __func__, req_num_pfxs, real_num_pfxs);
return MSG_NG;
}
return MSG_OK;
ltindex = lsatype & OSPF6_LSTYPE_FCODE_MASK;
if (ltindex < OSPF6_LSTYPE_SIZE && ospf6_lsa_minlen[ltindex]
&& lsalen < ospf6_lsa_minlen[ltindex] + OSPF6_LSA_HEADER_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized (%u B) LSA", __func__,
- lsalen);
+ zlog_warn("%s: undersized (%u B) LSA", __func__, lsalen);
return MSG_NG;
}
switch (lsatype) {
by N>=0 interface descriptions. */
if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_ROUTER_LSA_MIN_SIZE)
% OSPF6_ROUTER_LSDESC_FIX_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: interface description alignment error",
- __func__);
+ zlog_warn(
+ "%s: Router LSA interface description alignment error",
+ __func__);
return MSG_NG;
}
break;
if ((lsalen - OSPF6_LSA_HEADER_SIZE
- OSPF6_NETWORK_LSA_MIN_SIZE)
% OSPF6_NETWORK_LSDESC_FIX_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: router description alignment error",
- __func__);
+ zlog_warn(
+ "%s: Network LSA router description alignment error",
+ __func__);
return MSG_NG;
}
break;
/* RFC5340 A.4.6, fixed-size LSA. */
if (lsalen
> OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_ROUTER_LSA_FIX_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: oversized (%u B) LSA", __func__,
- lsalen);
+ zlog_warn("%s: Inter Router LSA oversized (%u B) LSA",
+ __func__, lsalen);
return MSG_NG;
}
break;
IPv6
prefix before ospf6_prefix_examin() confirms its sizing. */
if (exp_length + OSPF6_PREFIX_MIN_SIZE > lsalen) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized (%u B) LSA header",
- __func__, lsalen);
+ zlog_warn(
+ "%s: AS External undersized (%u B) LSA header",
+ __func__, lsalen);
return MSG_NG;
}
/* forwarding address */
I.e.,
this check does not include any IPv6 prefix fields. */
if (exp_length > lsalen) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized (%u B) LSA header",
- __func__, lsalen);
+ zlog_warn(
+ "%s: AS External undersized (%u B) LSA header",
+ __func__, lsalen);
return MSG_NG;
}
/* The last call completely covers the remainder (IPv6 prefix).
while (length) {
uint16_t lsalen;
if (length < OSPF6_LSA_HEADER_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: undersized (%zu B) trailing (#%u) LSA header",
- __func__, length, counted_lsas);
+ zlog_warn(
+ "%s: undersized (%zu B) trailing (#%u) LSA header",
+ __func__, length, counted_lsas);
return MSG_NG;
}
/* save on ntohs() calls here and in the LSA validator */
lsalen = OSPF6_LSA_SIZE(lsah);
if (lsalen < OSPF6_LSA_HEADER_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: malformed LSA header #%u, declared length is %u B",
- __func__, counted_lsas, lsalen);
+ zlog_warn(
+ "%s: malformed LSA header #%u, declared length is %u B",
+ __func__, counted_lsas, lsalen);
return MSG_NG;
}
if (headeronly) {
/* less checks here and in ospf6_lsa_examin() */
if (MSG_OK != ospf6_lsa_examin(lsah, lsalen, 1)) {
- if (IS_OSPF6_DEBUG_MESSAGE(
- OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: anomaly in header-only %s LSA #%u",
- __func__,
- ospf6_lstype_name(lsah->type),
- counted_lsas);
+ zlog_warn(
+ "%s: anomaly in header-only %s LSA #%u",
+ __func__, ospf6_lstype_name(lsah->type),
+ counted_lsas);
return MSG_NG;
}
lsah = (struct ospf6_lsa_header
/* make sure the input buffer is deep enough before
* further checks */
if (lsalen > length) {
- if (IS_OSPF6_DEBUG_MESSAGE(
- OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: anomaly in %s LSA #%u: declared length is %u B, buffered length is %zu B",
- __func__,
- ospf6_lstype_name(lsah->type),
- counted_lsas, lsalen, length);
+ zlog_warn(
+ "%s: anomaly in %s LSA #%u: declared length is %u B, buffered length is %zu B",
+ __func__, ospf6_lstype_name(lsah->type),
+ counted_lsas, lsalen, length);
return MSG_NG;
}
if (MSG_OK != ospf6_lsa_examin(lsah, lsalen, 0)) {
- if (IS_OSPF6_DEBUG_MESSAGE(
- OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: anomaly in %s LSA #%u",
- __func__,
- ospf6_lstype_name(lsah->type),
- counted_lsas);
+ zlog_warn("%s: anomaly in %s LSA #%u", __func__,
+ ospf6_lstype_name(lsah->type),
+ counted_lsas);
return MSG_NG;
}
lsah = (struct ospf6_lsa_header *)((caddr_t)lsah
}
if (declared_num_lsas && counted_lsas != declared_num_lsas) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: #LSAs declared (%u) does not match actual (%u)",
- __func__, declared_num_lsas, counted_lsas);
+ zlog_warn("%s: #LSAs declared (%u) does not match actual (%u)",
+ __func__, declared_num_lsas, counted_lsas);
return MSG_NG;
}
return MSG_OK;
/* length, 1st approximation */
if (bytesonwire < OSPF6_HEADER_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized (%u B) packet", __func__,
- bytesonwire);
+ zlog_warn("%s: undersized (%u B) packet", __func__,
+ bytesonwire);
return MSG_NG;
}
/* Now it is safe to access header fields. */
if (bytesonwire != ntohs(oh->length)) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: %s packet length error (%u real, %u declared)",
- __func__, lookup_msg(ospf6_message_type_str,
- oh->type, NULL),
- bytesonwire, ntohs(oh->length));
+ zlog_warn("%s: %s packet length error (%u real, %u declared)",
+ __func__,
+ lookup_msg(ospf6_message_type_str, oh->type, NULL),
+ bytesonwire, ntohs(oh->length));
return MSG_NG;
}
/* version check */
if (oh->version != OSPFV3_VERSION) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: invalid (%u) protocol version",
- __func__, oh->version);
+ zlog_warn("%s: invalid (%u) protocol version", __func__,
+ oh->version);
return MSG_NG;
}
/* length, 2nd approximation */
if (oh->type < OSPF6_MESSAGE_TYPE_ALL && ospf6_packet_minlen[oh->type]
&& bytesonwire
< OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type]) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized (%u B) %s packet", __func__,
- bytesonwire,
- lookup_msg(ospf6_message_type_str, oh->type,
- NULL));
+ zlog_warn("%s: undersized (%u B) %s packet", __func__,
+ bytesonwire,
+ lookup_msg(ospf6_message_type_str, oh->type, NULL));
return MSG_NG;
}
/* type-specific deeper validation */
== (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_HELLO_MIN_SIZE)
% 4)
return MSG_OK;
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: alignment error in %s packet", __func__,
- lookup_msg(ospf6_message_type_str, oh->type,
- NULL));
+ zlog_warn("%s: alignment error in %s packet", __func__,
+ lookup_msg(ospf6_message_type_str, oh->type, NULL));
return MSG_NG;
case OSPF6_MESSAGE_TYPE_DBDESC:
/* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes
== (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_REQ_MIN_SIZE)
% OSPF6_LSREQ_LSDESC_FIX_SIZE)
return MSG_OK;
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: alignment error in %s packet", __func__,
- lookup_msg(ospf6_message_type_str, oh->type,
- NULL));
+ zlog_warn("%s: alignment error in %s packet", __func__,
+ lookup_msg(ospf6_message_type_str, oh->type, NULL));
return MSG_NG;
case OSPF6_MESSAGE_TYPE_LSUPDATE:
/* RFC5340 A.3.5, packet header + OSPF6_LS_UPD_MIN_SIZE bytes
1, 0);
break;
default:
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: invalid (%u) message type", __func__,
- oh->type);
+ zlog_warn("%s: invalid (%u) message type", __func__, oh->type);
return MSG_NG;
}
- if (test != MSG_OK
- && IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV_HDR))
- zlog_debug("%s: anomaly in %s packet", __func__,
- lookup_msg(ospf6_message_type_str, oh->type, NULL));
+ if (test != MSG_OK)
+ zlog_warn("%s: anomaly in %s packet", __func__,
+ lookup_msg(ospf6_message_type_str, oh->type, NULL));
return test;
}
iobuflen = 0;
}
-int ospf6_receive(struct thread *thread)
+enum ospf6_read_return_enum {
+ OSPF6_READ_ERROR,
+ OSPF6_READ_CONTINUE,
+};
+
+static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6)
{
- int sockfd;
- unsigned int len;
+ int len;
struct in6_addr src, dst;
ifindex_t ifindex;
struct iovec iovector[2];
struct ospf6_interface *oi;
struct ospf6_header *oh;
- struct ospf6 *ospf6;
-
- /* add next read thread */
- ospf6 = THREAD_ARG(thread);
- sockfd = THREAD_FD(thread);
-
- thread_add_read(master, ospf6_receive, ospf6, ospf6->fd,
- &ospf6->t_ospf6_receive);
/* initialize */
memset(&src, 0, sizeof(src));
/* receive message */
len = ospf6_recvmsg(&src, &dst, &ifindex, iovector, sockfd);
- if (len > iobuflen) {
+ if (len < 0)
+ return OSPF6_READ_ERROR;
+
+ if ((uint)len > iobuflen) {
flog_err(EC_LIB_DEVELOPMENT, "Excess message read");
- return 0;
+ return OSPF6_READ_ERROR;
}
oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
RECV_HDR))
zlog_debug("Message received on disabled interface");
- return 0;
+ return OSPF6_READ_CONTINUE;
}
if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE)) {
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
RECV_HDR))
zlog_debug("%s: Ignore message on passive interface %s",
__func__, oi->interface->name);
- return 0;
+ return OSPF6_READ_CONTINUE;
}
+ /*
+ * Drop packet destined to another VRF.
+ * This happens when raw_l3mdev_accept is set to 1.
+ */
+ if (ospf6->vrf_id != oi->interface->vrf_id)
+ return OSPF6_READ_CONTINUE;
+
oh = (struct ospf6_header *)recvbuf;
if (ospf6_rxpacket_examin(oi, oh, len) != MSG_OK)
- return 0;
+ return OSPF6_READ_CONTINUE;
/* Being here means, that no sizing/alignment issues were detected in
the input packet. This renders the additional checks performed below
assert(0);
}
+ return OSPF6_READ_CONTINUE;
+}
+
+int ospf6_receive(struct thread *thread)
+{
+ int sockfd;
+ struct ospf6 *ospf6;
+ int count = 0;
+
+ /* add next read thread */
+ ospf6 = THREAD_ARG(thread);
+ sockfd = THREAD_FD(thread);
+
+ thread_add_read(master, ospf6_receive, ospf6, ospf6->fd,
+ &ospf6->t_ospf6_receive);
+
+ while (count < ospf6->write_oi_count) {
+ count++;
+ switch (ospf6_read_helper(sockfd, ospf6)) {
+ case OSPF6_READ_ERROR:
+ return 0;
+ case OSPF6_READ_CONTINUE:
+ break;
+ }
+ }
+
return 0;
}
-static void ospf6_send(struct in6_addr *src, struct in6_addr *dst,
- struct ospf6_interface *oi, struct ospf6_header *oh)
+static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi,
+ struct stream *s)
{
- unsigned int len;
- char srcname[64];
- struct iovec iovector[2];
+ struct ospf6_header *oh;
- /* initialize */
- iovector[0].iov_base = (caddr_t)oh;
- iovector[0].iov_len = ntohs(oh->length);
- iovector[1].iov_base = NULL;
- iovector[1].iov_len = 0;
+ oh = (struct ospf6_header *)STREAM_DATA(s);
+
+ oh->version = (uint8_t)OSPFV3_VERSION;
+ oh->type = type;
- /* fill OSPF header */
- oh->version = OSPFV3_VERSION;
- /* message type must be set before */
- /* message length must be set before */
oh->router_id = oi->area->ospf6->router_id;
oh->area_id = oi->area->area_id;
- /* checksum is calculated by kernel */
oh->instance_id = oi->instance_id;
oh->reserved = 0;
+ stream_forward_endp(s, OSPF6_HEADER_SIZE);
+}
- /* Log */
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) {
- if (src)
- inet_ntop(AF_INET6, src, srcname, sizeof(srcname));
- else
- memset(srcname, 0, sizeof(srcname));
- zlog_debug("%s send on %s",
- lookup_msg(ospf6_message_type_str, oh->type, NULL),
- oi->interface->name);
- zlog_debug(" src: %s", srcname);
- zlog_debug(" dst: %pI6", dst);
+static void ospf6_fill_header(struct ospf6_interface *oi, struct stream *s,
+ uint16_t length)
+{
+ struct ospf6_header *oh;
+
+ oh = (struct ospf6_header *)STREAM_DATA(s);
+
+ oh->length = htons(length);
+}
+
+static void ospf6_fill_lsupdate_header(struct stream *s, uint32_t lsa_num)
+{
+ struct ospf6_header *oh;
+ struct ospf6_lsupdate *lsu;
+
+ oh = (struct ospf6_header *)STREAM_DATA(s);
+
+ lsu = (struct ospf6_lsupdate *)((caddr_t)oh
+ + sizeof(struct ospf6_header));
+ lsu->lsa_number = htonl(lsa_num);
+}
+
+static uint32_t ospf6_packet_max(struct ospf6_interface *oi)
+{
+ assert(oi->ifmtu > sizeof(struct ip6_hdr));
+ return oi->ifmtu - (sizeof(struct ip6_hdr));
+}
+
+static uint16_t ospf6_make_hello(struct ospf6_interface *oi, struct stream *s)
+{
+ struct listnode *node, *nnode;
+ struct ospf6_neighbor *on;
+ uint16_t length = OSPF6_HELLO_MIN_SIZE;
+
+ stream_putl(s, oi->interface->ifindex);
+ stream_putc(s, oi->priority);
+ stream_putc(s, oi->area->options[0]);
+ stream_putc(s, oi->area->options[1]);
+ stream_putc(s, oi->area->options[2]);
+ stream_putw(s, oi->hello_interval);
+ stream_putw(s, oi->dead_interval);
+ stream_put_ipv4(s, oi->drouter);
+ stream_put_ipv4(s, oi->bdrouter);
+
+ for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
+ if (on->state < OSPF6_NEIGHBOR_INIT)
+ continue;
+
+ if ((length + sizeof(uint32_t) + OSPF6_HEADER_SIZE)
+ > ospf6_packet_max(oi)) {
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO,
+ SEND))
+ zlog_debug(
+ "sending Hello message: exceeds I/F MTU");
+ break;
+ }
+
+ stream_put_ipv4(s, on->router_id);
+ length += sizeof(uint32_t);
+ }
+
+ return length;
+}
+
+static int ospf6_write(struct thread *thread)
+{
+ struct ospf6 *ospf6 = THREAD_ARG(thread);
+ struct ospf6_interface *oi;
+ struct ospf6_interface *last_serviced_oi = NULL;
+ struct ospf6_header *oh;
+ struct ospf6_packet *op;
+ struct listnode *node;
+ struct iovec iovector[2];
+ int pkt_count = 0;
+ int len;
+ int64_t latency = 0;
+ struct timeval timestamp;
+
+ if (ospf6->fd < 0) {
+ zlog_warn("ospf6_write failed to send, fd %d", ospf6->fd);
+ return -1;
+ }
+
+ node = listhead(ospf6->oi_write_q);
+ assert(node);
+ oi = listgetdata(node);
+
+ while ((pkt_count < ospf6->write_oi_count) && oi
+ && (last_serviced_oi != oi)) {
+
+ op = ospf6_fifo_head(oi->obuf);
+ assert(op);
+ assert(op->length >= OSPF6_HEADER_SIZE);
+
+ iovector[0].iov_base = (caddr_t)stream_pnt(op->s);
+ iovector[0].iov_len = op->length;
+ iovector[1].iov_base = NULL;
+ iovector[1].iov_len = 0;
+
+ oh = (struct ospf6_header *)STREAM_DATA(op->s);
+
+ len = ospf6_sendmsg(oi->linklocal_addr, &op->dst,
+ oi->interface->ifindex, iovector,
+ ospf6->fd);
+ if (len != op->length)
+ flog_err(EC_LIB_DEVELOPMENT,
+ "Could not send entire message");
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) {
+ zlog_debug("%s send on %s",
+ lookup_msg(ospf6_message_type_str, oh->type,
+ NULL),
+ oi->interface->name);
+ zlog_debug(" src: %pI6", oi->linklocal_addr);
+ zlog_debug(" dst: %pI6", &op->dst);
+ switch (oh->type) {
+ case OSPF6_MESSAGE_TYPE_HELLO:
+ ospf6_hello_print(oh, OSPF6_ACTION_SEND);
+ break;
+ case OSPF6_MESSAGE_TYPE_DBDESC:
+ ospf6_dbdesc_print(oh, OSPF6_ACTION_SEND);
+ break;
+ case OSPF6_MESSAGE_TYPE_LSREQ:
+ ospf6_lsreq_print(oh, OSPF6_ACTION_SEND);
+ break;
+ case OSPF6_MESSAGE_TYPE_LSUPDATE:
+ ospf6_lsupdate_print(oh, OSPF6_ACTION_SEND);
+ break;
+ case OSPF6_MESSAGE_TYPE_LSACK:
+ ospf6_lsack_print(oh, OSPF6_ACTION_SEND);
+ break;
+ default:
+ zlog_debug("Unknown message");
+ assert(0);
+ break;
+ }
+ }
switch (oh->type) {
case OSPF6_MESSAGE_TYPE_HELLO:
- ospf6_hello_print(oh, OSPF6_ACTION_RECV);
+ monotime(×tamp);
+ if (oi->hello_out)
+ latency = monotime_since(&oi->last_hello, NULL)
+ - ((int64_t)oi->hello_interval
+ * 1000000);
+
+ /* log if latency exceeds the hello period */
+ if (latency > ((int64_t)oi->hello_interval * 1000000))
+ zlog_warn("%s hello TX high latency %" PRId64
+ "us.",
+ __func__, latency);
+ oi->last_hello = timestamp;
+ oi->hello_out++;
+ ospf6_hello_print(oh, OSPF6_ACTION_SEND);
break;
case OSPF6_MESSAGE_TYPE_DBDESC:
- ospf6_dbdesc_print(oh, OSPF6_ACTION_RECV);
+ oi->db_desc_out++;
break;
case OSPF6_MESSAGE_TYPE_LSREQ:
- ospf6_lsreq_print(oh, OSPF6_ACTION_RECV);
+ oi->ls_req_out++;
break;
case OSPF6_MESSAGE_TYPE_LSUPDATE:
- ospf6_lsupdate_print(oh, OSPF6_ACTION_RECV);
+ oi->ls_upd_out++;
break;
case OSPF6_MESSAGE_TYPE_LSACK:
- ospf6_lsack_print(oh, OSPF6_ACTION_RECV);
+ oi->ls_ack_out++;
break;
default:
zlog_debug("Unknown message");
assert(0);
break;
}
- }
+ /* Now delete packet from queue. */
+ ospf6_packet_delete(oi);
+
+ /* Move this interface to the tail of write_q to
+ serve everyone in a round robin fashion */
+ list_delete_node(ospf6->oi_write_q, node);
+ if (ospf6_fifo_head(oi->obuf) == NULL) {
+ oi->on_write_q = 0;
+ last_serviced_oi = NULL;
+ oi = NULL;
+ } else {
+ listnode_add(ospf6->oi_write_q, oi);
+ }
- /* send message */
- if (oi->area->ospf6->fd != -1) {
- len = ospf6_sendmsg(src, dst, oi->interface->ifindex, iovector,
- oi->area->ospf6->fd);
- if (len != ntohs(oh->length))
- flog_err(EC_LIB_DEVELOPMENT,
- "Could not send entire message");
+ /* Setup to service from the head of the queue again */
+ if (!list_isempty(ospf6->oi_write_q)) {
+ node = listhead(ospf6->oi_write_q);
+ oi = listgetdata(node);
+ }
}
-}
-static uint32_t ospf6_packet_max(struct ospf6_interface *oi)
-{
- assert(oi->ifmtu > sizeof(struct ip6_hdr));
- return oi->ifmtu - (sizeof(struct ip6_hdr));
+ /* If packets still remain in queue, call write thread. */
+ if (!list_isempty(ospf6->oi_write_q))
+ thread_add_write(master, ospf6_write, ospf6, ospf6->fd,
+ &ospf6->t_write);
+
+ return 0;
}
int ospf6_hello_send(struct thread *thread)
{
struct ospf6_interface *oi;
- struct ospf6_header *oh;
- struct ospf6_hello *hello;
- uint8_t *p;
- struct listnode *node, *nnode;
- struct ospf6_neighbor *on;
+ struct ospf6_packet *op;
+ uint16_t length = OSPF6_HEADER_SIZE;
oi = (struct ospf6_interface *)THREAD_ARG(thread);
oi->thread_send_hello = (struct thread *)NULL;
return 0;
}
- if (iobuflen == 0) {
- zlog_debug("Unable to send Hello on interface %s iobuflen is 0",
- oi->interface->name);
+ op = ospf6_packet_new(oi->ifmtu);
+
+ ospf6_make_header(OSPF6_MESSAGE_TYPE_HELLO, oi, op->s);
+
+ /* Prepare OSPF Hello body */
+ length += ospf6_make_hello(oi, op->s);
+ if (length == OSPF6_HEADER_SIZE) {
+ /* Hello overshooting MTU */
+ ospf6_packet_free(op);
return 0;
}
- /* set next thread */
- thread_add_timer(master, ospf6_hello_send, oi, oi->hello_interval,
- &oi->thread_send_hello);
+ /* Fill OSPF header. */
+ ospf6_fill_header(oi, op->s, length);
- memset(sendbuf, 0, iobuflen);
- oh = (struct ospf6_header *)sendbuf;
- hello = (struct ospf6_hello *)((caddr_t)oh
- + sizeof(struct ospf6_header));
+ /* Set packet length. */
+ op->length = length;
- hello->interface_id = htonl(oi->interface->ifindex);
- hello->priority = oi->priority;
- hello->options[0] = oi->area->options[0];
- hello->options[1] = oi->area->options[1];
- hello->options[2] = oi->area->options[2];
- hello->hello_interval = htons(oi->hello_interval);
- hello->dead_interval = htons(oi->dead_interval);
- hello->drouter = oi->drouter;
- hello->bdrouter = oi->bdrouter;
+ op->dst = allspfrouters6;
- p = (uint8_t *)((caddr_t)hello + sizeof(struct ospf6_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_packet_add_top(oi, op);
- for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
- if (on->state < OSPF6_NEIGHBOR_INIT)
- continue;
-
- if (p - sendbuf + sizeof(uint32_t) > ospf6_packet_max(oi)) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO,
- SEND_HDR))
- zlog_debug(
- "sending Hello message: exceeds I/F MTU");
- break;
- }
-
- memcpy(p, &on->router_id, sizeof(uint32_t));
- p += sizeof(uint32_t);
- }
-
- oh->type = OSPF6_MESSAGE_TYPE_HELLO;
- oh->length = htons(p - sendbuf);
+ /* set next thread */
+ thread_add_timer(master, ospf6_hello_send, oi, oi->hello_interval,
+ &oi->thread_send_hello);
- oi->hello_out++;
+ OSPF6_MESSAGE_WRITE_ON(oi);
- ospf6_send(oi->linklocal_addr, &allspfrouters6, oi, oh);
return 0;
}
-int ospf6_dbdesc_send(struct thread *thread)
+static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s)
{
- struct ospf6_neighbor *on;
- struct ospf6_header *oh;
- struct ospf6_dbdesc *dbdesc;
- uint8_t *p;
+ uint16_t length = OSPF6_DB_DESC_MIN_SIZE;
struct ospf6_lsa *lsa, *lsanext;
- struct in6_addr *dst;
-
- on = (struct ospf6_neighbor *)THREAD_ARG(thread);
- on->thread_send_dbdesc = (struct thread *)NULL;
-
- if (on->state < OSPF6_NEIGHBOR_EXSTART) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_DBDESC, SEND_HDR))
- zlog_debug(
- "Quit to send DbDesc to neighbor %s state %s",
- on->name, ospf6_neighbor_state_str[on->state]);
- return 0;
- }
-
- /* set next thread if master */
- if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT))
- thread_add_timer(master, ospf6_dbdesc_send, on,
- on->ospf6_if->rxmt_interval,
- &on->thread_send_dbdesc);
-
- memset(sendbuf, 0, iobuflen);
- oh = (struct ospf6_header *)sendbuf;
- dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh
- + sizeof(struct ospf6_header));
/* if this is initial one, initialize sequence number for DbDesc */
if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
on->dbdesc_seqnum = monotime(NULL);
}
- dbdesc->options[0] = on->ospf6_if->area->options[0];
- dbdesc->options[1] = on->ospf6_if->area->options[1];
- dbdesc->options[2] = on->ospf6_if->area->options[2];
- dbdesc->ifmtu = htons(on->ospf6_if->ifmtu);
- dbdesc->bits = on->dbdesc_bits;
- dbdesc->seqnum = htonl(on->dbdesc_seqnum);
+ /* reserved */
+ stream_putc(s, 0); /* reserved 1 */
+ stream_putc(s, on->ospf6_if->area->options[0]);
+ stream_putc(s, on->ospf6_if->area->options[1]);
+ stream_putc(s, on->ospf6_if->area->options[2]);
+ stream_putw(s, on->ospf6_if->ifmtu);
+ stream_putc(s, 0); /* reserved 2 */
+ stream_putc(s, on->dbdesc_bits);
+ stream_putl(s, on->dbdesc_seqnum);
/* if this is not initial one, set LSA headers in dbdesc */
- p = (uint8_t *)((caddr_t)dbdesc + sizeof(struct ospf6_dbdesc));
if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)) {
for (ALL_LSDB(on->dbdesc_list, lsa, lsanext)) {
ospf6_lsa_age_update_to_send(lsa,
on->ospf6_if->transdelay);
/* MTU check */
- if (p - sendbuf + sizeof(struct ospf6_lsa_header)
+ if ((length + sizeof(struct ospf6_lsa_header)
+ + OSPF6_HEADER_SIZE)
> ospf6_packet_max(on->ospf6_if)) {
ospf6_lsa_unlock(lsa);
if (lsanext)
ospf6_lsa_unlock(lsanext);
break;
}
- memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header));
- p += sizeof(struct ospf6_lsa_header);
+ stream_put(s, lsa->header,
+ sizeof(struct ospf6_lsa_header));
+ length += sizeof(struct ospf6_lsa_header);
}
}
+ return length;
+}
- oh->type = OSPF6_MESSAGE_TYPE_DBDESC;
- oh->length = htons(p - sendbuf);
+int ospf6_dbdesc_send(struct thread *thread)
+{
+ struct ospf6_neighbor *on;
+ uint16_t length = OSPF6_HEADER_SIZE;
+ struct ospf6_packet *op;
+ on = (struct ospf6_neighbor *)THREAD_ARG(thread);
+ on->thread_send_dbdesc = (struct thread *)NULL;
+
+ if (on->state < OSPF6_NEIGHBOR_EXSTART) {
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_DBDESC, SEND))
+ zlog_debug(
+ "Quit to send DbDesc to neighbor %s state %s",
+ on->name, ospf6_neighbor_state_str[on->state]);
+ return 0;
+ }
+
+ /* set next thread if master */
+ if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT))
+ thread_add_timer(master, ospf6_dbdesc_send, on,
+ on->ospf6_if->rxmt_interval,
+ &on->thread_send_dbdesc);
+
+ op = ospf6_packet_new(on->ospf6_if->ifmtu);
+ ospf6_make_header(OSPF6_MESSAGE_TYPE_DBDESC, on->ospf6_if, op->s);
+
+ length += ospf6_make_dbdesc(on, op->s);
+ ospf6_fill_header(on->ospf6_if, op->s, length);
+
+ /* Set packet length. */
+ op->length = length;
if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
- dst = &allspfrouters6;
+ op->dst = allspfrouters6;
else
- dst = &on->linklocal_addr;
+ op->dst = on->linklocal_addr;
- on->ospf6_if->db_desc_out++;
+ ospf6_packet_add(on->ospf6_if, op);
- ospf6_send(on->ospf6_if->linklocal_addr, dst, on->ospf6_if, oh);
+ OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
return 0;
}
size = sizeof(struct ospf6_lsa_header) + sizeof(struct ospf6_dbdesc);
for (ALL_LSDB(on->summary_list, lsa, lsanext)) {
/* if stub area then don't advertise AS-External LSAs */
- if (IS_AREA_STUB(on->ospf6_if->area)
+ if ((IS_AREA_STUB(on->ospf6_if->area)
+ || IS_AREA_NSSA(on->ospf6_if->area))
&& ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
ospf6_lsdb_remove(lsa, on->summary_list);
continue;
return 0;
}
+static uint16_t ospf6_make_lsreq(struct ospf6_neighbor *on, struct stream *s)
+{
+ uint16_t length = 0;
+ struct ospf6_lsa *lsa, *lsanext, *last_req = NULL;
+
+ for (ALL_LSDB(on->request_list, lsa, lsanext)) {
+ if ((length + OSPF6_HEADER_SIZE)
+ > ospf6_packet_max(on->ospf6_if)) {
+ ospf6_lsa_unlock(lsa);
+ if (lsanext)
+ ospf6_lsa_unlock(lsanext);
+ break;
+ }
+ stream_putw(s, 0); /* reserved */
+ stream_putw(s, ntohs(lsa->header->type));
+ stream_putl(s, ntohl(lsa->header->id));
+ stream_putl(s, ntohl(lsa->header->adv_router));
+ length += sizeof(struct ospf6_lsreq_entry);
+ last_req = lsa;
+ }
+
+ if (last_req != NULL) {
+ if (on->last_ls_req != NULL)
+ on->last_ls_req = ospf6_lsa_unlock(on->last_ls_req);
+
+ ospf6_lsa_lock(last_req);
+ on->last_ls_req = last_req;
+ }
+
+ return length;
+}
+
+static uint16_t ospf6_make_lsack_neighbor(struct ospf6_neighbor *on,
+ struct ospf6_packet **op)
+{
+ uint16_t length = 0;
+ struct ospf6_lsa *lsa, *lsanext;
+ int lsa_cnt = 0;
+
+ for (ALL_LSDB(on->lsack_list, lsa, lsanext)) {
+ if ((length + sizeof(struct ospf6_lsa_header)
+ + OSPF6_HEADER_SIZE)
+ > ospf6_packet_max(on->ospf6_if)) {
+ /* if we run out of packet size/space here,
+ better to try again soon. */
+ if (lsa_cnt) {
+ ospf6_fill_header(on->ospf6_if, (*op)->s,
+ length + OSPF6_HEADER_SIZE);
+
+ (*op)->length = length + OSPF6_HEADER_SIZE;
+ (*op)->dst = on->linklocal_addr;
+ ospf6_packet_add(on->ospf6_if, *op);
+ OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
+ /* new packet */
+ *op = ospf6_packet_new(on->ospf6_if->ifmtu);
+ ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK,
+ on->ospf6_if, (*op)->s);
+ length = 0;
+ lsa_cnt = 0;
+ }
+ }
+ ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
+ stream_put((*op)->s, lsa->header,
+ sizeof(struct ospf6_lsa_header));
+ length += sizeof(struct ospf6_lsa_header);
+
+ assert(lsa->lock == 2);
+ ospf6_lsdb_remove(lsa, on->lsack_list);
+ lsa_cnt++;
+ }
+ return length;
+}
+
int ospf6_lsreq_send(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_header *oh;
- struct ospf6_lsreq_entry *e;
- uint8_t *p;
- struct ospf6_lsa *lsa, *lsanext, *last_req;
+ struct ospf6_packet *op;
+ uint16_t length = OSPF6_HEADER_SIZE;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
on->thread_send_lsreq = (struct thread *)NULL;
return 0;
}
- memset(sendbuf, 0, iobuflen);
- oh = (struct ospf6_header *)sendbuf;
- last_req = NULL;
+ op = ospf6_packet_new(on->ospf6_if->ifmtu);
+ ospf6_make_header(OSPF6_MESSAGE_TYPE_LSREQ, on->ospf6_if, op->s);
- /* set Request entries in lsreq */
- p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header));
- for (ALL_LSDB(on->request_list, lsa, lsanext)) {
- /* MTU check */
- if (p - sendbuf + sizeof(struct ospf6_lsreq_entry)
- > ospf6_packet_max(on->ospf6_if)) {
- ospf6_lsa_unlock(lsa);
- if (lsanext)
- ospf6_lsa_unlock(lsanext);
- break;
- }
-
- e = (struct ospf6_lsreq_entry *)p;
- e->type = lsa->header->type;
- e->id = lsa->header->id;
- e->adv_router = lsa->header->adv_router;
- p += sizeof(struct ospf6_lsreq_entry);
- last_req = lsa;
- }
+ length += ospf6_make_lsreq(on, op->s);
- if (last_req != NULL) {
- if (on->last_ls_req != NULL)
- on->last_ls_req = ospf6_lsa_unlock(on->last_ls_req);
-
- ospf6_lsa_lock(last_req);
- on->last_ls_req = last_req;
+ if (length == OSPF6_HEADER_SIZE) {
+ /* Hello overshooting MTU */
+ ospf6_packet_free(op);
+ return 0;
}
- oh->type = OSPF6_MESSAGE_TYPE_LSREQ;
- oh->length = htons(p - sendbuf);
+ /* Fill OSPF header. */
+ ospf6_fill_header(on->ospf6_if, op->s, length);
- on->ospf6_if->ls_req_out++;
+ /* Set packet length */
+ op->length = length;
if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
- ospf6_send(on->ospf6_if->linklocal_addr, &allspfrouters6,
- on->ospf6_if, oh);
+ op->dst = allspfrouters6;
else
- ospf6_send(on->ospf6_if->linklocal_addr, &on->linklocal_addr,
- on->ospf6_if, oh);
+ op->dst = on->linklocal_addr;
+
+ ospf6_packet_add(on->ospf6_if, op);
+
+ OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
/* set next thread */
if (on->request_list->count != 0) {
static void ospf6_send_lsupdate(struct ospf6_neighbor *on,
struct ospf6_interface *oi,
- struct ospf6_header *oh)
+ struct ospf6_packet *op)
{
if (on) {
- on->ospf6_if->ls_upd_out++;
if ((on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
|| (on->ospf6_if->state == OSPF6_INTERFACE_DR)
- || (on->ospf6_if->state == OSPF6_INTERFACE_BDR)) {
- ospf6_send(on->ospf6_if->linklocal_addr,
- &allspfrouters6, on->ospf6_if, oh);
- } else {
- ospf6_send(on->ospf6_if->linklocal_addr,
- &on->linklocal_addr, on->ospf6_if, oh);
- }
+ || (on->ospf6_if->state == OSPF6_INTERFACE_BDR))
+ op->dst = allspfrouters6;
+ else
+ op->dst = on->linklocal_addr;
+ oi = on->ospf6_if;
} else if (oi) {
-
- oi->ls_upd_out++;
-
if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT)
|| (oi->state == OSPF6_INTERFACE_DR)
- || (oi->state == OSPF6_INTERFACE_BDR)) {
- ospf6_send(oi->linklocal_addr, &allspfrouters6, oi, oh);
- } else {
- ospf6_send(oi->linklocal_addr, &alldrouters6, oi, oh);
+ || (oi->state == OSPF6_INTERFACE_BDR))
+ op->dst = allspfrouters6;
+ else
+ op->dst = alldrouters6;
+ }
+ if (oi) {
+ ospf6_packet_add(oi, op);
+ /* If ospf instance is being deleted, send the packet
+ * immediately
+ */
+ if ((oi->area == NULL) || (oi->area->ospf6 == NULL))
+ return;
+ if (oi->area->ospf6->inst_shutdown) {
+ if (oi->on_write_q == 0) {
+ listnode_add(oi->area->ospf6->oi_write_q, oi);
+ oi->on_write_q = 1;
+ }
+ thread_execute(master, ospf6_write, oi->area->ospf6, 0);
+ } else
+ OSPF6_MESSAGE_WRITE_ON(oi);
+ }
+}
+
+static uint16_t ospf6_make_lsupdate_list(struct ospf6_neighbor *on,
+ struct ospf6_packet **op, int *lsa_cnt)
+{
+ uint16_t length = OSPF6_LS_UPD_MIN_SIZE;
+ struct ospf6_lsa *lsa, *lsanext;
+
+ /* skip over fixed header */
+ stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
+
+ for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) {
+ if ((length + (unsigned int)OSPF6_LSA_SIZE(lsa->header)
+ + OSPF6_HEADER_SIZE)
+ > ospf6_packet_max(on->ospf6_if)) {
+ ospf6_fill_header(on->ospf6_if, (*op)->s,
+ length + OSPF6_HEADER_SIZE);
+ (*op)->length = length + OSPF6_HEADER_SIZE;
+ ospf6_fill_lsupdate_header((*op)->s, *lsa_cnt);
+ ospf6_send_lsupdate(on, NULL, *op);
+
+ /* refresh packet */
+ *op = ospf6_packet_new(on->ospf6_if->ifmtu);
+ length = OSPF6_LS_UPD_MIN_SIZE;
+ *lsa_cnt = 0;
+ ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE,
+ on->ospf6_if, (*op)->s);
+ stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
}
+ ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
+ stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
+ (*lsa_cnt)++;
+ length += OSPF6_LSA_SIZE(lsa->header);
+ assert(lsa->lock == 2);
+ ospf6_lsdb_remove(lsa, on->lsupdate_list);
}
+ return length;
+}
+
+static uint16_t ospf6_make_ls_retrans_list(struct ospf6_neighbor *on,
+ struct ospf6_packet **op,
+ int *lsa_cnt)
+{
+ uint16_t length = OSPF6_LS_UPD_MIN_SIZE;
+ struct ospf6_lsa *lsa, *lsanext;
+
+ /* skip over fixed header */
+ stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
+
+ for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
+ if ((length + (unsigned int)OSPF6_LSA_SIZE(lsa->header)
+ + OSPF6_HEADER_SIZE)
+ > ospf6_packet_max(on->ospf6_if)) {
+ ospf6_fill_header(on->ospf6_if, (*op)->s,
+ length + OSPF6_HEADER_SIZE);
+ (*op)->length = length + OSPF6_HEADER_SIZE;
+ ospf6_fill_lsupdate_header((*op)->s, *lsa_cnt);
+ if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
+ (*op)->dst = allspfrouters6;
+ else
+ (*op)->dst = on->linklocal_addr;
+
+ ospf6_packet_add(on->ospf6_if, *op);
+ OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
+
+ /* refresh packet */
+ *op = ospf6_packet_new(on->ospf6_if->ifmtu);
+ length = OSPF6_LS_UPD_MIN_SIZE;
+ *lsa_cnt = 0;
+ ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE,
+ on->ospf6_if, (*op)->s);
+ stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
+ }
+ ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
+ stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
+ (*lsa_cnt)++;
+ length += OSPF6_LSA_SIZE(lsa->header);
+ }
+ return length;
}
int ospf6_lsupdate_send_neighbor(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_header *oh;
- struct ospf6_lsupdate *lsupdate;
- uint8_t *p;
- int lsa_cnt;
- struct ospf6_lsa *lsa, *lsanext;
+ struct ospf6_packet *op;
+ uint16_t length = OSPF6_HEADER_SIZE;
+ int lsa_cnt = 0;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
on->thread_send_lsupdate = (struct thread *)NULL;
return 0;
}
- memset(sendbuf, 0, iobuflen);
- oh = (struct ospf6_header *)sendbuf;
- lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
- + sizeof(struct ospf6_header));
-
- p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
- lsa_cnt = 0;
-
- /* lsupdate_list lists those LSA which doesn't need to be
- retransmitted. remove those from the list */
- for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) {
- /* MTU check */
- if ((p - sendbuf + (unsigned int)OSPF6_LSA_SIZE(lsa->header))
- > ospf6_packet_max(on->ospf6_if)) {
- if (lsa_cnt) {
- oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
- oh->length = htons(p - sendbuf);
- lsupdate->lsa_number = htonl(lsa_cnt);
-
- ospf6_send_lsupdate(on, NULL, oh);
-
- memset(sendbuf, 0, iobuflen);
- oh = (struct ospf6_header *)sendbuf;
- lsupdate = (struct ospf6_lsupdate
- *)((caddr_t)oh
- + sizeof(struct
- ospf6_header));
-
- p = (uint8_t *)((caddr_t)lsupdate
- + sizeof(struct
- ospf6_lsupdate));
- lsa_cnt = 0;
- }
- }
-
- ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
- memcpy(p, lsa->header, OSPF6_LSA_SIZE(lsa->header));
- p += OSPF6_LSA_SIZE(lsa->header);
- lsa_cnt++;
-
- assert(lsa->lock == 2);
- ospf6_lsdb_remove(lsa, on->lsupdate_list);
- }
-
+ /* first do lsupdate_list */
+ op = ospf6_packet_new(on->ospf6_if->ifmtu);
+ ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, on->ospf6_if, op->s);
+ length += ospf6_make_lsupdate_list(on, &op, &lsa_cnt);
if (lsa_cnt) {
- oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
- oh->length = htons(p - sendbuf);
- lsupdate->lsa_number = htonl(lsa_cnt);
- ospf6_send_lsupdate(on, NULL, oh);
- }
-
- /* The addresses used for retransmissions are different from those sent
- the
- first time and so we need to separate them here.
- */
- memset(sendbuf, 0, iobuflen);
- oh = (struct ospf6_header *)sendbuf;
- lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
- + sizeof(struct ospf6_header));
- p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
- lsa_cnt = 0;
-
- for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
- /* MTU check */
- if ((p - sendbuf + (unsigned int)OSPF6_LSA_SIZE(lsa->header))
- > ospf6_packet_max(on->ospf6_if)) {
- if (lsa_cnt) {
- oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
- oh->length = htons(p - sendbuf);
- lsupdate->lsa_number = htonl(lsa_cnt);
-
- if (on->ospf6_if->state
- == OSPF6_INTERFACE_POINTTOPOINT) {
- ospf6_send(on->ospf6_if->linklocal_addr,
- &allspfrouters6,
- on->ospf6_if, oh);
- } else {
- ospf6_send(on->ospf6_if->linklocal_addr,
- &on->linklocal_addr,
- on->ospf6_if, oh);
- }
-
- memset(sendbuf, 0, iobuflen);
- oh = (struct ospf6_header *)sendbuf;
- lsupdate = (struct ospf6_lsupdate
- *)((caddr_t)oh
- + sizeof(struct
- ospf6_header));
- p = (uint8_t *)((caddr_t)lsupdate
- + sizeof(struct
- ospf6_lsupdate));
- lsa_cnt = 0;
- }
- }
-
- ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
- memcpy(p, lsa->header, OSPF6_LSA_SIZE(lsa->header));
- p += OSPF6_LSA_SIZE(lsa->header);
- lsa_cnt++;
- }
-
+ /* Fill OSPF header. */
+ ospf6_fill_header(on->ospf6_if, op->s, length);
+ ospf6_fill_lsupdate_header(op->s, lsa_cnt);
+ op->length = length;
+ ospf6_send_lsupdate(on, NULL, op);
+
+ /* prepare new packet */
+ op = ospf6_packet_new(on->ospf6_if->ifmtu);
+ length = OSPF6_HEADER_SIZE;
+ lsa_cnt = 0;
+ } else {
+ stream_reset(op->s);
+ length = OSPF6_HEADER_SIZE;
+ }
+
+ ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, on->ospf6_if, op->s);
+ /* now do retransmit list */
+ length += ospf6_make_ls_retrans_list(on, &op, &lsa_cnt);
if (lsa_cnt) {
- oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
- oh->length = htons(p - sendbuf);
- lsupdate->lsa_number = htonl(lsa_cnt);
-
+ ospf6_fill_header(on->ospf6_if, op->s, length);
+ ospf6_fill_lsupdate_header(op->s, lsa_cnt);
+ op->length = length;
if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
- ospf6_send(on->ospf6_if->linklocal_addr,
- &allspfrouters6, on->ospf6_if, oh);
+ op->dst = allspfrouters6;
else
- ospf6_send(on->ospf6_if->linklocal_addr,
- &on->linklocal_addr, on->ospf6_if, oh);
- }
+ op->dst = on->linklocal_addr;
+ ospf6_packet_add(on->ospf6_if, op);
+ OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
+ } else
+ ospf6_packet_free(op);
if (on->lsupdate_list->count != 0) {
on->thread_send_lsupdate = NULL;
int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on,
struct ospf6_lsa *lsa)
{
- struct ospf6_header *oh;
- struct ospf6_lsupdate *lsupdate;
- uint8_t *p;
- int lsa_cnt = 0;
+ struct ospf6_packet *op;
+ uint16_t length = OSPF6_HEADER_SIZE;
- memset(sendbuf, 0, iobuflen);
- oh = (struct ospf6_header *)sendbuf;
- lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
- + sizeof(struct ospf6_header));
+ op = ospf6_packet_new(on->ospf6_if->ifmtu);
+ ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, on->ospf6_if, op->s);
- p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
+ /* skip over fixed header */
+ stream_forward_endp(op->s, OSPF6_LS_UPD_MIN_SIZE);
ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
- memcpy(p, lsa->header, OSPF6_LSA_SIZE(lsa->header));
- p += OSPF6_LSA_SIZE(lsa->header);
- lsa_cnt++;
-
- oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
- oh->length = htons(p - sendbuf);
- lsupdate->lsa_number = htonl(lsa_cnt);
+ stream_put(op->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
+ length = OSPF6_HEADER_SIZE + OSPF6_LS_UPD_MIN_SIZE
+ + OSPF6_LSA_SIZE(lsa->header);
+ ospf6_fill_header(on->ospf6_if, op->s, length);
+ ospf6_fill_lsupdate_header(op->s, 1);
+ op->length = length;
if (IS_OSPF6_DEBUG_FLOODING
|| IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND_HDR))
zlog_debug("%s: Send lsupdate with lsa %s (age %u)", __func__,
lsa->name, ntohs(lsa->header->age));
- ospf6_send_lsupdate(on, NULL, oh);
+ ospf6_send_lsupdate(on, NULL, op);
return 0;
}
+static uint16_t ospf6_make_lsupdate_interface(struct ospf6_interface *oi,
+ struct ospf6_packet **op,
+ int *lsa_cnt)
+{
+ uint16_t length = OSPF6_LS_UPD_MIN_SIZE;
+ struct ospf6_lsa *lsa, *lsanext;
+
+ /* skip over fixed header */
+ stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
+
+ for (ALL_LSDB(oi->lsupdate_list, lsa, lsanext)) {
+ if (length + (unsigned int)OSPF6_LSA_SIZE(lsa->header)
+ + OSPF6_HEADER_SIZE
+ > ospf6_packet_max(oi)) {
+ ospf6_fill_header(oi, (*op)->s,
+ length + OSPF6_HEADER_SIZE);
+ (*op)->length = length + OSPF6_HEADER_SIZE;
+ ospf6_fill_lsupdate_header((*op)->s, *lsa_cnt);
+ ospf6_send_lsupdate(NULL, oi, *op);
+
+ /* refresh packet */
+ *op = ospf6_packet_new(oi->ifmtu);
+ length = OSPF6_LS_UPD_MIN_SIZE;
+ *lsa_cnt = 0;
+ ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, oi,
+ (*op)->s);
+ stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
+ }
+
+ ospf6_lsa_age_update_to_send(lsa, oi->transdelay);
+ stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
+ (*lsa_cnt)++;
+ length += OSPF6_LSA_SIZE(lsa->header);
+
+ assert(lsa->lock == 2);
+ ospf6_lsdb_remove(lsa, oi->lsupdate_list);
+ }
+ return length;
+}
+
int ospf6_lsupdate_send_interface(struct thread *thread)
{
struct ospf6_interface *oi;
- struct ospf6_header *oh;
- struct ospf6_lsupdate *lsupdate;
- uint8_t *p;
- int lsa_cnt;
- struct ospf6_lsa *lsa, *lsanext;
+ struct ospf6_packet *op;
+ uint16_t length = OSPF6_HEADER_SIZE;
+ int lsa_cnt = 0;
oi = (struct ospf6_interface *)THREAD_ARG(thread);
oi->thread_send_lsupdate = (struct thread *)NULL;
if (oi->lsupdate_list->count == 0)
return 0;
- memset(sendbuf, 0, iobuflen);
- oh = (struct ospf6_header *)sendbuf;
- lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
- + sizeof(struct ospf6_header));
-
- p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
- lsa_cnt = 0;
-
- for (ALL_LSDB(oi->lsupdate_list, lsa, lsanext)) {
- /* MTU check */
- if ((p - sendbuf + ((unsigned int)OSPF6_LSA_SIZE(lsa->header)))
- > ospf6_packet_max(oi)) {
- if (lsa_cnt) {
- oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
- oh->length = htons(p - sendbuf);
- lsupdate->lsa_number = htonl(lsa_cnt);
-
- ospf6_send_lsupdate(NULL, oi, oh);
- if (IS_OSPF6_DEBUG_MESSAGE(
- OSPF6_MESSAGE_TYPE_LSUPDATE, SEND))
- zlog_debug("%s: LSUpdate length %d",
- __func__, ntohs(oh->length));
-
- memset(sendbuf, 0, iobuflen);
- oh = (struct ospf6_header *)sendbuf;
- lsupdate = (struct ospf6_lsupdate
- *)((caddr_t)oh
- + sizeof(struct
- ospf6_header));
-
- p = (uint8_t *)((caddr_t)lsupdate
- + sizeof(struct
- ospf6_lsupdate));
- lsa_cnt = 0;
- }
- }
-
- ospf6_lsa_age_update_to_send(lsa, oi->transdelay);
- memcpy(p, lsa->header, OSPF6_LSA_SIZE(lsa->header));
- p += OSPF6_LSA_SIZE(lsa->header);
- lsa_cnt++;
-
- assert(lsa->lock == 2);
- ospf6_lsdb_remove(lsa, oi->lsupdate_list);
- }
-
+ op = ospf6_packet_new(oi->ifmtu);
+ ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, oi, op->s);
+ length += ospf6_make_lsupdate_interface(oi, &op, &lsa_cnt);
if (lsa_cnt) {
- oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
- oh->length = htons(p - sendbuf);
- lsupdate->lsa_number = htonl(lsa_cnt);
-
- ospf6_send_lsupdate(NULL, oi, oh);
- }
+ /* Fill OSPF header. */
+ ospf6_fill_header(oi, op->s, length);
+ ospf6_fill_lsupdate_header(op->s, lsa_cnt);
+ op->length = length;
+ ospf6_send_lsupdate(NULL, oi, op);
+ } else
+ ospf6_packet_free(op);
if (oi->lsupdate_list->count > 0) {
oi->thread_send_lsupdate = NULL;
int ospf6_lsack_send_neighbor(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_header *oh;
- uint8_t *p;
- struct ospf6_lsa *lsa, *lsanext;
- int lsa_cnt = 0;
+ struct ospf6_packet *op;
+ uint16_t length = OSPF6_HEADER_SIZE;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
on->thread_send_lsack = (struct thread *)NULL;
if (on->lsack_list->count == 0)
return 0;
- memset(sendbuf, 0, iobuflen);
- oh = (struct ospf6_header *)sendbuf;
-
- p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header));
+ op = ospf6_packet_new(on->ospf6_if->ifmtu);
+ ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK, on->ospf6_if, op->s);
- for (ALL_LSDB(on->lsack_list, lsa, lsanext)) {
- /* MTU check */
- if (p - sendbuf + sizeof(struct ospf6_lsa_header)
- > ospf6_packet_max(on->ospf6_if)) {
- /* if we run out of packet size/space here,
- better to try again soon. */
- if (lsa_cnt) {
- oh->type = OSPF6_MESSAGE_TYPE_LSACK;
- oh->length = htons(p - sendbuf);
-
- on->ospf6_if->ls_ack_out++;
-
- ospf6_send(on->ospf6_if->linklocal_addr,
- &on->linklocal_addr, on->ospf6_if,
- oh);
-
- memset(sendbuf, 0, iobuflen);
- oh = (struct ospf6_header *)sendbuf;
- p = (uint8_t *)((caddr_t)oh
- + sizeof(struct ospf6_header));
- lsa_cnt = 0;
- }
- }
-
- ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
- memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header));
- p += sizeof(struct ospf6_lsa_header);
+ length += ospf6_make_lsack_neighbor(on, &op);
- assert(lsa->lock == 2);
- ospf6_lsdb_remove(lsa, on->lsack_list);
- lsa_cnt++;
+ if (length == OSPF6_HEADER_SIZE) {
+ ospf6_packet_free(op);
+ return 0;
}
- if (lsa_cnt) {
- oh->type = OSPF6_MESSAGE_TYPE_LSACK;
- oh->length = htons(p - sendbuf);
-
- on->ospf6_if->ls_ack_out++;
+ /* Fill OSPF header. */
+ ospf6_fill_header(on->ospf6_if, op->s, length);
- ospf6_send(on->ospf6_if->linklocal_addr, &on->linklocal_addr,
- on->ospf6_if, oh);
- }
+ /* Set packet length, dst and queue to FIFO. */
+ op->length = length;
+ op->dst = on->linklocal_addr;
+ ospf6_packet_add(on->ospf6_if, op);
+ OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
if (on->lsack_list->count > 0)
thread_add_event(master, ospf6_lsack_send_neighbor, on, 0,
return 0;
}
+static uint16_t ospf6_make_lsack_interface(struct ospf6_interface *oi,
+ struct ospf6_packet *op)
+{
+ uint16_t length = 0;
+ struct ospf6_lsa *lsa, *lsanext;
+
+ for (ALL_LSDB(oi->lsack_list, lsa, lsanext)) {
+ if ((length + sizeof(struct ospf6_lsa_header)
+ + OSPF6_HEADER_SIZE)
+ > ospf6_packet_max(oi)) {
+ /* if we run out of packet size/space here,
+ better to try again soon. */
+ THREAD_OFF(oi->thread_send_lsack);
+ thread_add_event(master, ospf6_lsack_send_interface, oi,
+ 0, &oi->thread_send_lsack);
+
+ ospf6_lsa_unlock(lsa);
+ if (lsanext)
+ ospf6_lsa_unlock(lsanext);
+ break;
+ }
+ ospf6_lsa_age_update_to_send(lsa, oi->transdelay);
+ stream_put(op->s, lsa->header, sizeof(struct ospf6_lsa_header));
+ length += sizeof(struct ospf6_lsa_header);
+
+ assert(lsa->lock == 2);
+ ospf6_lsdb_remove(lsa, oi->lsack_list);
+ }
+ return length;
+}
+
int ospf6_lsack_send_interface(struct thread *thread)
{
struct ospf6_interface *oi;
- struct ospf6_header *oh;
- uint8_t *p;
- struct ospf6_lsa *lsa, *lsanext;
- int lsa_cnt = 0;
+ struct ospf6_packet *op;
+ uint16_t length = OSPF6_HEADER_SIZE;
oi = (struct ospf6_interface *)THREAD_ARG(thread);
oi->thread_send_lsack = (struct thread *)NULL;
if (oi->lsack_list->count == 0)
return 0;
- memset(sendbuf, 0, iobuflen);
- oh = (struct ospf6_header *)sendbuf;
-
- p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header));
+ op = ospf6_packet_new(oi->ifmtu);
+ ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK, oi, op->s);
- for (ALL_LSDB(oi->lsack_list, lsa, lsanext)) {
- /* MTU check */
- if (p - sendbuf + sizeof(struct ospf6_lsa_header)
- > ospf6_packet_max(oi)) {
- /* if we run out of packet size/space here,
- better to try again soon. */
- THREAD_OFF(oi->thread_send_lsack);
- thread_add_event(master, ospf6_lsack_send_interface, oi,
- 0, &oi->thread_send_lsack);
+ length += ospf6_make_lsack_interface(oi, op);
- ospf6_lsa_unlock(lsa);
- if (lsanext)
- ospf6_lsa_unlock(lsanext);
- break;
- }
-
- ospf6_lsa_age_update_to_send(lsa, oi->transdelay);
- memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header));
- p += sizeof(struct ospf6_lsa_header);
-
- assert(lsa->lock == 2);
- ospf6_lsdb_remove(lsa, oi->lsack_list);
- lsa_cnt++;
+ if (length == OSPF6_HEADER_SIZE) {
+ ospf6_packet_free(op);
+ return 0;
}
+ /* Fill OSPF header. */
+ ospf6_fill_header(oi, op->s, length);
- if (lsa_cnt) {
- oh->type = OSPF6_MESSAGE_TYPE_LSACK;
- oh->length = htons(p - sendbuf);
+ /* Set packet length, dst and queue to FIFO. */
+ op->length = length;
+ if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT)
+ || (oi->state == OSPF6_INTERFACE_DR)
+ || (oi->state == OSPF6_INTERFACE_BDR))
+ op->dst = allspfrouters6;
+ else
+ op->dst = alldrouters6;
- if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT)
- || (oi->state == OSPF6_INTERFACE_DR)
- || (oi->state == OSPF6_INTERFACE_BDR))
- ospf6_send(oi->linklocal_addr, &allspfrouters6, oi, oh);
- else
- ospf6_send(oi->linklocal_addr, &alldrouters6, oi, oh);
- }
+ ospf6_packet_add(oi, op);
+ OSPF6_MESSAGE_WRITE_ON(oi);
if (oi->lsack_list->count > 0)
thread_add_event(master, ospf6_lsack_send_interface, oi, 0,
return 0;
}
-
/* Commands */
DEFUN(debug_ospf6_message, debug_ospf6_message_cmd,
"debug ospf6 message <unknown|hello|dbdesc|lsreq|lsupdate|lsack|all> [<send|recv|send-hdr|recv-hdr>]",