From ec44732ea3e9a84639defc4f054e017f7087fe05 Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Wed, 3 Mar 2021 11:17:38 +0000 Subject: [PATCH 01/13] ospf6d: create an ospf_read_helper function Take the contents of ospf6_receive and split the funtionality that deals with a single packet receipt and place it in a separate helper function. This is the first step in a refactor process to allow the ospf6_read task to read until failure. Signed-off-by: Pat Ruddy --- ospf6d/ospf6_message.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 9a1d8b79bc..1afcf78a8f 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1572,23 +1572,14 @@ void ospf6_message_terminate(void) iobuflen = 0; } -int ospf6_receive(struct thread *thread) +static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) { - int sockfd; unsigned 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)); @@ -1689,6 +1680,21 @@ int ospf6_receive(struct thread *thread) return 0; } +int ospf6_receive(struct thread *thread) +{ + int sockfd; + 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); + + return ospf6_read_helper(sockfd, ospf6); +} + static void ospf6_send(struct in6_addr *src, struct in6_addr *dst, struct ospf6_interface *oi, struct ospf6_header *oh) { From aa6a96ba78bacb2792f2a6c26b6873b3ff4e35b8 Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Wed, 3 Mar 2021 11:59:30 +0000 Subject: [PATCH 02/13] ospf6d: read ospf6 socket until failure To ensure we read all the datagrams availabe from a socket when the read task is scheduled, make the read helper return and error or continue enum and loop unitl an error is received. This requires the read from the socket to be non blocking Signed-off-by: Pat Ruddy --- ospf6d/ospf6_message.c | 35 +++++++++++++++++++++++++++-------- ospf6d/ospf6_network.c | 11 +++++++---- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 1afcf78a8f..e6d09b9a08 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1572,9 +1572,14 @@ void ospf6_message_terminate(void) iobuflen = 0; } +enum ospf6_read_return_enum { + OSPF6_READ_ERROR, + OSPF6_READ_CONTINUE, +}; + static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) { - unsigned int len; + int len; struct in6_addr src, dst; ifindex_t ifindex; struct iovec iovector[2]; @@ -1593,9 +1598,12 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) /* 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); @@ -1604,19 +1612,19 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) 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; } 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 @@ -1677,13 +1685,14 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) assert(0); } - return 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); @@ -1692,7 +1701,17 @@ int ospf6_receive(struct thread *thread) thread_add_read(master, ospf6_receive, ospf6, ospf6->fd, &ospf6->t_ospf6_receive); - return ospf6_read_helper(sockfd, ospf6); + while (count < 20) { + 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, diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index 76f98fecdd..5961cfe66a 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -257,10 +257,13 @@ int ospf6_recvmsg(struct in6_addr *src, struct in6_addr *dst, rmsghdr.msg_control = (caddr_t)cmsgbuf; rmsghdr.msg_controllen = sizeof(cmsgbuf); - retval = recvmsg(ospf6_sock, &rmsghdr, 0); - if (retval < 0) - zlog_warn("recvmsg failed: %s", safe_strerror(errno)); - else if (retval == iov_totallen(message)) + retval = recvmsg(ospf6_sock, &rmsghdr, MSG_DONTWAIT); + if (retval < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) + zlog_warn("stream_recvmsg failed: %s", + safe_strerror(errno)); + return retval; + } else if (retval == iov_totallen(message)) zlog_warn("recvmsg read full buffer size: %d", retval); /* source address */ From 4f7bf1ab052e82f16f8b965c6afe9d1c0f22f479 Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Wed, 10 Mar 2021 17:59:07 +0000 Subject: [PATCH 03/13] ospf6d: add tx fifo infrastructure Add per interface fifo and per instance write list as a precursor to implementing fairer sharing of the ospf6 oscket resources. Signed-off-by: Pat Ruddy --- ospf6d/ospf6_interface.c | 13 ++++++ ospf6d/ospf6_interface.h | 5 +++ ospf6d/ospf6_message.c | 91 ++++++++++++++++++++++++++++++++++++++++ ospf6d/ospf6_message.h | 30 +++++++++++++ ospf6d/ospf6_top.c | 3 ++ ospf6d/ospf6_top.h | 2 + 6 files changed, 144 insertions(+) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 952c7f8b27..57b7348bcc 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -185,6 +185,8 @@ struct ospf6_interface *ospf6_interface_create(struct interface *ifp) oi = XCALLOC(MTYPE_OSPF6_IF, sizeof(struct ospf6_interface)); + oi->obuf = ospf6_fifo_new(); + oi->area = (struct ospf6_area *)NULL; oi->neighbor_list = list_new(); oi->neighbor_list->cmp = ospf6_neighbor_cmp; @@ -243,6 +245,8 @@ void ospf6_interface_delete(struct ospf6_interface *oi) QOBJ_UNREG(oi); + ospf6_fifo_free(oi->obuf); + for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) ospf6_neighbor_delete(on); @@ -888,6 +892,15 @@ int interface_down(struct thread *thread) ospf6_sso(oi->interface->ifindex, &allspfrouters6, IPV6_LEAVE_GROUP, ospf6->fd); + /* deal with write fifo */ + ospf6_fifo_flush(oi->obuf); + if (oi->on_write_q) { + listnode_delete(ospf6->oi_write_q, oi); + if (list_isempty(ospf6->oi_write_q)) + thread_cancel(&ospf6->t_write); + oi->on_write_q = 0; + } + ospf6_interface_state_change(OSPF6_INTERFACE_DOWN, oi); return 0; diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 796d75e897..bbed03539d 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -56,6 +56,9 @@ struct ospf6_interface { /* I/F transmission delay */ uint32_t transdelay; + /* Packet send buffer. */ + struct ospf6_fifo *obuf; /* Output queue */ + /* Network Type */ uint8_t type; bool type_cfg; @@ -130,6 +133,8 @@ struct ospf6_interface { char *profile; } bfd_config; + int on_write_q; + /* Statistics Fields */ uint32_t hello_in; uint32_t hello_out; diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index e6d09b9a08..8f9ae7b0c4 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -50,6 +50,8 @@ #include 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[] = { @@ -252,6 +254,95 @@ void ospf6_lsack_print(struct ospf6_header *oh, int action) } } +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. */ +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. */ +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. */ +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. */ +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_hello_recv(struct in6_addr *src, struct in6_addr *dst, struct ospf6_interface *oi, struct ospf6_header *oh) diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h index 7c108bd452..4069e10486 100644 --- a/ospf6d/ospf6_message.h +++ b/ospf6d/ospf6_message.h @@ -63,6 +63,27 @@ extern unsigned char conf_debug_ospf6_message[]; #define OSPF6_MESSAGE_TYPE_LSACK 0x5 /* Flooding acknowledgment */ #define OSPF6_MESSAGE_TYPE_ALL 0x6 /* For debug option */ +struct ospf6_packet { + struct ospf6_packet *next; + + /* Pointer to data stream. */ + struct stream *s; + + /* IP destination address. */ + struct in6_addr dst; + + /* OSPF6 packet length. */ + uint16_t length; +}; + +/* OSPF packet queue structure. */ +struct ospf6_fifo { + unsigned long count; + + struct ospf6_packet *head; + struct ospf6_packet *tail; +}; + /* OSPFv3 packet header */ #define OSPF6_HEADER_SIZE 16U struct ospf6_header { @@ -136,6 +157,15 @@ extern void ospf6_lsreq_print(struct ospf6_header *, int action); extern void ospf6_lsupdate_print(struct ospf6_header *, int action); extern void ospf6_lsack_print(struct ospf6_header *, int action); +extern void ospf6_packet_free(struct ospf6_packet *op); +extern struct ospf6_fifo *ospf6_fifo_new(void); +extern void ospf6_fifo_push(struct ospf6_fifo *fifo, struct ospf6_packet *op); +void ospf6_fifo_push_head(struct ospf6_fifo *fifo, struct ospf6_packet *op); +extern struct ospf6_packet *ospf6_fifo_pop(struct ospf6_fifo *fifo); +extern struct ospf6_packet *ospf6_fifo_head(struct ospf6_fifo *fifo); +extern void ospf6_fifo_flush(struct ospf6_fifo *fifo); +extern void ospf6_fifo_free(struct ospf6_fifo *fifo); + extern int ospf6_iobuf_size(unsigned int size); extern void ospf6_message_terminate(void); extern int ospf6_receive(struct thread *thread); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index cd1b5b99f8..adfedcc49c 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -413,6 +413,8 @@ static struct ospf6 *ospf6_create(const char *name) o->max_multipath = MULTIPATH_NUM; + o->oi_write_q = list_new(); + QOBJ_REG(o, ospf6); /* Make ospf protocol socket. */ @@ -482,6 +484,7 @@ void ospf6_delete(struct ospf6 *o) ospf6_distance_reset(o); route_table_finish(o->distance_table); + list_delete(&o->oi_write_q); if (o->vrf_id != VRF_UNKNOWN) { vrf = vrf_lookup_by_id(o->vrf_id); diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index e4dfebe1de..1386ffd379 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -128,6 +128,7 @@ struct ospf6 { struct thread *maxage_remover; struct thread *t_distribute_update; /* Distirbute update timer. */ struct thread *t_ospf6_receive; /* OSPF6 receive timer */ + struct thread *t_write; uint32_t ref_bandwidth; @@ -150,6 +151,7 @@ struct ospf6 { /* Count of NSSA areas */ uint8_t anyNSSA; struct thread *t_abr_task; /* ABR task timer. */ + struct list *oi_write_q; uint32_t redist_count; QOBJ_FIELDS; From 531f925b4d22778ebcd93158757e105de0217f87 Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Wed, 10 Mar 2021 18:40:14 +0000 Subject: [PATCH 04/13] ospf6d: add packet apis Add APIs to create, queue and dequeue OSPFv3 packets Signed-off-by: Pat Ruddy --- ospf6d/ospf6_message.c | 36 +++++++++++++++++++++++++++++++++--- ospf6d/ospf6_message.h | 13 +++++++++---- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 8f9ae7b0c4..70ad735764 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -271,7 +271,7 @@ struct ospf6_fifo *ospf6_fifo_new(void) } /* Add new packet to fifo. */ -void ospf6_fifo_push(struct ospf6_fifo *fifo, struct ospf6_packet *op) +static void ospf6_fifo_push(struct ospf6_fifo *fifo, struct ospf6_packet *op) { if (fifo->tail) fifo->tail->next = op; @@ -284,7 +284,8 @@ void ospf6_fifo_push(struct ospf6_fifo *fifo, struct ospf6_packet *op) } /* Add new packet to head of fifo. */ -void ospf6_fifo_push_head(struct ospf6_fifo *fifo, struct ospf6_packet *op) +static void ospf6_fifo_push_head(struct ospf6_fifo *fifo, + struct ospf6_packet *op) { op->next = fifo->head; @@ -297,7 +298,7 @@ void ospf6_fifo_push_head(struct ospf6_fifo *fifo, struct ospf6_packet *op) } /* Delete first packet from fifo. */ -struct ospf6_packet *ospf6_fifo_pop(struct ospf6_fifo *fifo) +static struct ospf6_packet *ospf6_fifo_pop(struct ospf6_fifo *fifo) { struct ospf6_packet *op; @@ -343,6 +344,35 @@ void ospf6_fifo_free(struct ospf6_fifo *fifo) XFREE(MTYPE_OSPF6_FIFO, fifo); } +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); */ +} + +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); */ +} + +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) diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h index 4069e10486..c7a5434e59 100644 --- a/ospf6d/ospf6_message.h +++ b/ospf6d/ospf6_message.h @@ -159,12 +159,17 @@ extern void ospf6_lsack_print(struct ospf6_header *, int action); extern void ospf6_packet_free(struct ospf6_packet *op); extern struct ospf6_fifo *ospf6_fifo_new(void); -extern void ospf6_fifo_push(struct ospf6_fifo *fifo, struct ospf6_packet *op); -void ospf6_fifo_push_head(struct ospf6_fifo *fifo, struct ospf6_packet *op); -extern struct ospf6_packet *ospf6_fifo_pop(struct ospf6_fifo *fifo); -extern struct ospf6_packet *ospf6_fifo_head(struct ospf6_fifo *fifo); extern void ospf6_fifo_flush(struct ospf6_fifo *fifo); extern void ospf6_fifo_free(struct ospf6_fifo *fifo); +struct ospf6_packet *ospf6_fifo_head(struct ospf6_fifo *fifo); + +/* temporary inclusinon of ospf6_interface.h for compile will be removed */ +#include "ospf6_interface.h" +extern void ospf6_packet_add(struct ospf6_interface *oi, + struct ospf6_packet *op); +extern void ospf6_packet_add_top(struct ospf6_interface *oi, + struct ospf6_packet *op); +extern void ospf6_packet_delete(struct ospf6_interface *oi); extern int ospf6_iobuf_size(unsigned int size); extern void ospf6_message_terminate(void); From 3d9680313e663a6f906db9cf87b568cb25b62b9b Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Fri, 12 Mar 2021 10:56:28 +0000 Subject: [PATCH 05/13] ospf6d: add hello messages to tx fifo queue outgoing hello messages to the interface tx FIFO and schedule the ospf_write task to deal with them. Signed-off-by: Pat Ruddy --- ospf6d/ospf6_message.c | 273 ++++++++++++++++++++++++++++++++--------- ospf6d/ospf6_message.h | 3 - ospf6d/ospf6_network.h | 15 +++ ospf6d/ospf6_top.h | 1 + 4 files changed, 233 insertions(+), 59 deletions(-) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 70ad735764..16af80b597 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -254,6 +254,16 @@ void ospf6_lsack_print(struct ospf6_header *oh, int action) } } +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; +} + void ospf6_packet_free(struct ospf6_packet *op) { if (op->s) @@ -353,7 +363,8 @@ void ospf6_packet_add(struct ospf6_interface *oi, struct ospf6_packet *op) /* ospf_fifo_debug (oi->obuf); */ } -void ospf6_packet_add_top(struct ospf6_interface *oi, struct ospf6_packet *op) +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); @@ -362,7 +373,7 @@ void ospf6_packet_add_top(struct ospf6_interface *oi, struct ospf6_packet *op) /* ospf_fifo_debug (oi->obuf); */ } -void ospf6_packet_delete(struct ospf6_interface *oi) +static void ospf6_packet_delete(struct ospf6_interface *oi) { struct ospf6_packet *op; @@ -1822,7 +1833,7 @@ int ospf6_receive(struct thread *thread) thread_add_read(master, ospf6_receive, ospf6, ospf6->fd, &ospf6->t_ospf6_receive); - while (count < 20) { + while (count < OSPF6_WRITE_INTERFACE_COUNT_DEFAULT) { count++; switch (ospf6_read_helper(sockfd, ospf6)) { case OSPF6_READ_ERROR: @@ -1835,6 +1846,184 @@ int ospf6_receive(struct thread *thread) return 0; } +static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi, + struct stream *s) +{ + struct ospf6_header *oh; + + oh = (struct ospf6_header *)STREAM_DATA(s); + + oh->version = (uint8_t)OSPFV3_VERSION; + oh->type = type; + + oh->router_id = oi->area->ospf6->router_id; + oh->area_id = oi->area->area_id; + oh->instance_id = oi->instance_id; + oh->reserved = 0; + stream_forward_endp(s, OSPF6_HEADER_SIZE); +} + +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 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; + char srcname[64], dstname[64]; + struct iovec iovector[2]; + int pkt_count = 0; + int len; + + 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_INTERFACE_COUNT_DEFAULT) && 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)) { + inet_ntop(AF_INET6, &op->dst, dstname, sizeof(dstname)); + inet_ntop(AF_INET6, oi->linklocal_addr, srcname, + 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: %s", dstname); + } + switch (oh->type) { + case OSPF6_MESSAGE_TYPE_HELLO: + oi->hello_out++; + ospf6_hello_print(oh, OSPF6_ACTION_SEND); + break; + case OSPF6_MESSAGE_TYPE_DBDESC: + oi->db_desc_out++; + ospf6_dbdesc_print(oh, OSPF6_ACTION_SEND); + break; + case OSPF6_MESSAGE_TYPE_LSREQ: + oi->ls_req_out++; + ospf6_lsreq_print(oh, OSPF6_ACTION_SEND); + break; + case OSPF6_MESSAGE_TYPE_LSUPDATE: + oi->ls_upd_out++; + ospf6_lsupdate_print(oh, OSPF6_ACTION_SEND); + break; + case OSPF6_MESSAGE_TYPE_LSACK: + oi->ls_ack_out++; + ospf6_lsack_print(oh, OSPF6_ACTION_SEND); + 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); + } + + /* 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); + } + } + + /* 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; +} + static void ospf6_send(struct in6_addr *src, struct in6_addr *dst, struct ospf6_interface *oi, struct ospf6_header *oh) { @@ -1903,20 +2092,11 @@ static void ospf6_send(struct in6_addr *src, struct in6_addr *dst, } } -static uint32_t ospf6_packet_max(struct ospf6_interface *oi) -{ - assert(oi->ifmtu > sizeof(struct ip6_hdr)); - return oi->ifmtu - (sizeof(struct ip6_hdr)); -} - 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; @@ -1928,55 +2108,37 @@ int ospf6_hello_send(struct thread *thread) 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; } + /* Fill OSPF header. */ + ospf6_fill_header(oi, op->s, length); + + /* Set packet length. */ + op->length = length; + + op->dst = allspfrouters6; + + /* 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); + /* set next thread */ thread_add_timer(master, ospf6_hello_send, oi, oi->hello_interval, &oi->thread_send_hello); - memset(sendbuf, 0, iobuflen); - oh = (struct ospf6_header *)sendbuf; - hello = (struct ospf6_hello *)((caddr_t)oh - + sizeof(struct ospf6_header)); + OSPF6_MESSAGE_WRITE_ON(oi->area->ospf6); - 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; - - p = (uint8_t *)((caddr_t)hello + sizeof(struct ospf6_hello)); - - 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); - - oi->hello_out++; - - ospf6_send(oi->linklocal_addr, &allspfrouters6, oi, oh); return 0; } @@ -2644,7 +2806,6 @@ int ospf6_lsack_send_interface(struct thread *thread) return 0; } - /* Commands */ DEFUN(debug_ospf6_message, debug_ospf6_message_cmd, "debug ospf6 message []", diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h index c7a5434e59..447a90c773 100644 --- a/ospf6d/ospf6_message.h +++ b/ospf6d/ospf6_message.h @@ -167,9 +167,6 @@ struct ospf6_packet *ospf6_fifo_head(struct ospf6_fifo *fifo); #include "ospf6_interface.h" extern void ospf6_packet_add(struct ospf6_interface *oi, struct ospf6_packet *op); -extern void ospf6_packet_add_top(struct ospf6_interface *oi, - struct ospf6_packet *op); -extern void ospf6_packet_delete(struct ospf6_interface *oi); extern int ospf6_iobuf_size(unsigned int size); extern void ospf6_message_terminate(void); diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h index 08d8be4445..5b476c4593 100644 --- a/ospf6d/ospf6_network.h +++ b/ospf6d/ospf6_network.h @@ -36,4 +36,19 @@ extern int ospf6_recvmsg(struct in6_addr *src, struct in6_addr *dst, ifindex_t *ifindex, struct iovec *message, int ospf6_sock); +#define OSPF6_MESSAGE_WRITE_ON(O) \ + do { \ + bool list_was_empty = \ + list_isempty(oi->area->ospf6->oi_write_q); \ + if ((oi)->on_write_q == 0) { \ + listnode_add(oi->area->ospf6->oi_write_q, (oi)); \ + (oi)->on_write_q = 1; \ + } \ + if (list_was_empty \ + && !list_isempty(oi->area->ospf6->oi_write_q)) \ + thread_add_write(master, ospf6_write, oi->area->ospf6, \ + oi->area->ospf6->fd, \ + &oi->area->ospf6->t_write); \ + } while (0) + #endif /* OSPF6_NETWORK_H */ diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 1386ffd379..dfd6893983 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -128,6 +128,7 @@ struct ospf6 { struct thread *maxage_remover; struct thread *t_distribute_update; /* Distirbute update timer. */ struct thread *t_ospf6_receive; /* OSPF6 receive timer */ +#define OSPF6_WRITE_INTERFACE_COUNT_DEFAULT 20 struct thread *t_write; uint32_t ref_bandwidth; From d6a39b53f52299307cca20b850ba2b271f761a00 Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Fri, 12 Mar 2021 10:58:22 +0000 Subject: [PATCH 06/13] ospf6d: add dbdesc messages to tx FIFO enqueue outgoing dbdesc messages to the end of the tx FIFO and schedule the ospf6_write task to deal with them. Signed-off-by: Pat Ruddy --- ospf6d/ospf6_message.c | 115 ++++++++++++++++++++++------------------- ospf6d/ospf6_message.h | 7 --- ospf6d/ospf6_network.h | 2 +- 3 files changed, 63 insertions(+), 61 deletions(-) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 16af80b597..10ce92f655 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -264,7 +264,7 @@ static struct ospf6_packet *ospf6_packet_new(size_t size) return new; } -void ospf6_packet_free(struct ospf6_packet *op) +static void ospf6_packet_free(struct ospf6_packet *op) { if (op->s) stream_free(op->s); @@ -327,7 +327,7 @@ static struct ospf6_packet *ospf6_fifo_pop(struct ospf6_fifo *fifo) } /* Return first fifo entry. */ -struct ospf6_packet *ospf6_fifo_head(struct ospf6_fifo *fifo) +static struct ospf6_packet *ospf6_fifo_head(struct ospf6_fifo *fifo) { return fifo->head; } @@ -354,7 +354,8 @@ void ospf6_fifo_free(struct ospf6_fifo *fifo) XFREE(MTYPE_OSPF6_FIFO, fifo); } -void ospf6_packet_add(struct ospf6_interface *oi, struct ospf6_packet *op) +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); @@ -2137,25 +2138,66 @@ int ospf6_hello_send(struct thread *thread) thread_add_timer(master, ospf6_hello_send, oi, oi->hello_interval, &oi->thread_send_hello); - OSPF6_MESSAGE_WRITE_ON(oi->area->ospf6); + OSPF6_MESSAGE_WRITE_ON(oi); return 0; } +static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s) +{ + uint16_t length = OSPF6_DB_DESC_MIN_SIZE; + struct ospf6_lsa *lsa, *lsanext; + + /* if this is initial one, initialize sequence number for DbDesc */ + if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT) + && (on->dbdesc_seqnum == 0)) { + on->dbdesc_seqnum = monotime(NULL); + } + + /* 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 */ + 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 ((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; + } + stream_put(s, lsa->header, + sizeof(struct ospf6_lsa_header)); + length += sizeof(struct ospf6_lsa_header); + } + } + return length; +} + int ospf6_dbdesc_send(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_header *oh; - struct ospf6_dbdesc *dbdesc; - uint8_t *p; - struct ospf6_lsa *lsa, *lsanext; - struct in6_addr *dst; + 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_HDR)) + 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]); @@ -2168,56 +2210,23 @@ int ospf6_dbdesc_send(struct thread *thread) 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)); + op = ospf6_packet_new(on->ospf6_if->ifmtu); + ospf6_make_header(OSPF6_MESSAGE_TYPE_DBDESC, on->ospf6_if, op->s); - /* if this is initial one, initialize sequence number for DbDesc */ - if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT) - && (on->dbdesc_seqnum == 0)) { - 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); - - /* 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) - > 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); - } - } - - oh->type = OSPF6_MESSAGE_TYPE_DBDESC; - oh->length = htons(p - sendbuf); + 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; } diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h index 447a90c773..0cd10ef825 100644 --- a/ospf6d/ospf6_message.h +++ b/ospf6d/ospf6_message.h @@ -157,16 +157,9 @@ extern void ospf6_lsreq_print(struct ospf6_header *, int action); extern void ospf6_lsupdate_print(struct ospf6_header *, int action); extern void ospf6_lsack_print(struct ospf6_header *, int action); -extern void ospf6_packet_free(struct ospf6_packet *op); extern struct ospf6_fifo *ospf6_fifo_new(void); extern void ospf6_fifo_flush(struct ospf6_fifo *fifo); extern void ospf6_fifo_free(struct ospf6_fifo *fifo); -struct ospf6_packet *ospf6_fifo_head(struct ospf6_fifo *fifo); - -/* temporary inclusinon of ospf6_interface.h for compile will be removed */ -#include "ospf6_interface.h" -extern void ospf6_packet_add(struct ospf6_interface *oi, - struct ospf6_packet *op); extern int ospf6_iobuf_size(unsigned int size); extern void ospf6_message_terminate(void); diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h index 5b476c4593..3886a0d263 100644 --- a/ospf6d/ospf6_network.h +++ b/ospf6d/ospf6_network.h @@ -36,7 +36,7 @@ extern int ospf6_recvmsg(struct in6_addr *src, struct in6_addr *dst, ifindex_t *ifindex, struct iovec *message, int ospf6_sock); -#define OSPF6_MESSAGE_WRITE_ON(O) \ +#define OSPF6_MESSAGE_WRITE_ON(oi) \ do { \ bool list_was_empty = \ list_isempty(oi->area->ospf6->oi_write_q); \ From 571eed235dfb1a78942a17df5fabf60989b228b9 Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Mon, 15 Mar 2021 18:17:02 +0000 Subject: [PATCH 07/13] ospf6d: add lsreq messages to tx fifo queue outgoing lsreq messages to the interface tx FIFO and schedule the ospf_write task to deal with them. Signed-off-by: Pat Ruddy --- ospf6d/ospf6_message.c | 90 ++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 10ce92f655..1459c02c9d 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -2279,13 +2279,43 @@ int ospf6_dbdesc_send_newone(struct thread *thread) 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; +} + 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; @@ -2306,49 +2336,31 @@ int ospf6_lsreq_send(struct thread *thread) 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; - } + length += ospf6_make_lsreq(on, op->s); - 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; + if (length == OSPF6_HEADER_SIZE) { + /* Hello overshooting MTU */ + ospf6_packet_free(op); + return 0; } - if (last_req != NULL) { - if (on->last_ls_req != NULL) - on->last_ls_req = ospf6_lsa_unlock(on->last_ls_req); + /* Fill OSPF header. */ + ospf6_fill_header(on->ospf6_if, op->s, length); - ospf6_lsa_lock(last_req); - on->last_ls_req = last_req; - } - - oh->type = OSPF6_MESSAGE_TYPE_LSREQ; - oh->length = htons(p - sendbuf); - - 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) { From dd784cf9fa6d1df103b608a30fa3194d8625b206 Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Wed, 17 Mar 2021 14:42:01 +0000 Subject: [PATCH 08/13] ospf6d: add lsack messages to tx fifo queue outgoing lsack messages to the interface tx FIFO and schedule the ospf_write task to deal with them. Signed-off-by: Pat Ruddy --- ospf6d/ospf6_message.c | 195 +++++++++++++++++++++++------------------ 1 file changed, 108 insertions(+), 87 deletions(-) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 1459c02c9d..a65b774a4d 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -2311,6 +2311,47 @@ static uint16_t ospf6_make_lsreq(struct ospf6_neighbor *on, struct stream *s) 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; @@ -2350,7 +2391,7 @@ int ospf6_lsreq_send(struct thread *thread) /* Fill OSPF header. */ ospf6_fill_header(on->ospf6_if, op->s, length); - /* Set packet length. */ + /* Set packet length */ op->length = length; if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) @@ -2679,10 +2720,8 @@ int ospf6_lsupdate_send_interface(struct thread *thread) 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; @@ -2699,53 +2738,24 @@ int ospf6_lsack_send_neighbor(struct thread *thread) if (on->lsack_list->count == 0) return 0; - memset(sendbuf, 0, iobuflen); - oh = (struct ospf6_header *)sendbuf; + op = ospf6_packet_new(on->ospf6_if->ifmtu); + ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK, on->ospf6_if, op->s); - p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header)); + length += ospf6_make_lsack_neighbor(on, &op); - 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); - - 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); + /* Fill OSPF header. */ + ospf6_fill_header(on->ospf6_if, op->s, length); - on->ospf6_if->ls_ack_out++; - - 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, @@ -2754,13 +2764,42 @@ int ospf6_lsack_send_neighbor(struct thread *thread) 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; @@ -2778,47 +2817,29 @@ int ospf6_lsack_send_interface(struct thread *thread) if (oi->lsack_list->count == 0) return 0; - memset(sendbuf, 0, iobuflen); - oh = (struct ospf6_header *)sendbuf; + op = ospf6_packet_new(oi->ifmtu); + ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK, oi, op->s); - p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header)); + length += ospf6_make_lsack_interface(oi, op); - 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); - - 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, From 432b7daf3dbaf8bacc8fc2282185a2fd937c4c2d Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Thu, 18 Mar 2021 14:39:36 +0000 Subject: [PATCH 09/13] ospf6d: add lsupdate messages to tx fifo queue outgoing lsupdate messages to the interface tx FIFO and schedule the ospf_write task to deal with them. Signed-off-by: Pat Ruddy --- ospf6d/ospf6_message.c | 474 ++++++++++++++++++----------------------- 1 file changed, 203 insertions(+), 271 deletions(-) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index a65b774a4d..a2d678dfad 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1874,6 +1874,18 @@ static void ospf6_fill_header(struct ospf6_interface *oi, struct stream *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)); @@ -2025,74 +2037,6 @@ static int ospf6_write(struct thread *thread) return 0; } -static void ospf6_send(struct in6_addr *src, struct in6_addr *dst, - struct ospf6_interface *oi, struct ospf6_header *oh) -{ - unsigned int len; - char srcname[64]; - struct iovec iovector[2]; - - /* 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; - - /* 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; - - /* 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); - - switch (oh->type) { - case OSPF6_MESSAGE_TYPE_HELLO: - ospf6_hello_print(oh, OSPF6_ACTION_RECV); - break; - case OSPF6_MESSAGE_TYPE_DBDESC: - ospf6_dbdesc_print(oh, OSPF6_ACTION_RECV); - break; - case OSPF6_MESSAGE_TYPE_LSREQ: - ospf6_lsreq_print(oh, OSPF6_ACTION_RECV); - break; - case OSPF6_MESSAGE_TYPE_LSUPDATE: - ospf6_lsupdate_print(oh, OSPF6_ACTION_RECV); - break; - case OSPF6_MESSAGE_TYPE_LSACK: - ospf6_lsack_print(oh, OSPF6_ACTION_RECV); - break; - default: - zlog_debug("Unknown message"); - assert(0); - break; - } - } - - /* 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"); - } -} - int ospf6_hello_send(struct thread *thread) { struct ospf6_interface *oi; @@ -2416,43 +2360,117 @@ int ospf6_lsreq_send(struct thread *thread) 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); + 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; @@ -2468,119 +2486,41 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) 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; @@ -2598,44 +2538,78 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) 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; @@ -2654,59 +2628,17 @@ int ospf6_lsupdate_send_interface(struct thread *thread) 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; From bb382e24f1f4a6d526e71163abf11d965e5258e2 Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Tue, 13 Apr 2021 10:37:51 +0100 Subject: [PATCH 10/13] ospf6d: add warning log for late hello packets On transmit and receive calculate the time since the last hello was seen and log a warning if it is late by more than the hello period. Signed-off-by: Pat Ruddy --- ospf6d/ospf6_interface.h | 3 +++ ospf6d/ospf6_message.c | 27 +++++++++++++++++++++++++++ ospf6d/ospf6_neighbor.h | 4 ++++ 3 files changed, 34 insertions(+) diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index bbed03539d..530efc3bd2 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -121,6 +121,9 @@ struct ospf6_interface { struct ospf6_route_table *route_connected; + /* last hello sent */ + struct timeval last_hello; + /* prefix-list name to filter connected prefix */ char *plist_name; diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index a2d678dfad..95ea4b5c14 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -396,7 +396,10 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, 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)); @@ -438,6 +441,17 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, on->priority = hello->priority; } + /* check latency against hello period */ + if (on->hello_in) + latency = monotime_since(&on->last_hello, NULL) + - (oi->hello_interval * 1000000); + /* log if latency exceeds the hello period */ + if (latency > (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)); @@ -1940,6 +1954,8 @@ static int ospf6_write(struct thread *thread) 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); @@ -1984,6 +2000,17 @@ static int ospf6_write(struct thread *thread) } switch (oh->type) { case OSPF6_MESSAGE_TYPE_HELLO: + monotime(×tamp); + if (oi->hello_out) + latency = monotime_since(&oi->last_hello, NULL) + - (oi->hello_interval * 1000000); + + /* log if latency exceeds the hello period */ + if (latency > (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; diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index 47f8c834e2..4e37050783 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -47,6 +47,10 @@ struct ospf6_neighbor { uint32_t state_change; struct timeval last_changed; + /* last received hello */ + struct timeval last_hello; + uint32_t hello_in; + /* Neighbor Router ID */ in_addr_t router_id; From 78156066b9aae203d7346f5ff3250a1ff40839be Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Thu, 6 May 2021 11:39:58 +0100 Subject: [PATCH 11/13] ospf6d: add write-multiplier configuration allow amount of work done by read and write threads in a single invocation to be tuned to between 1 and 100 packets (default 20) Signed-off-by: Pat Ruddy --- ospf6d/ospf6_interface.c | 35 +++++++++++++++++++++++++++++++++++ ospf6d/ospf6_message.c | 4 ++-- ospf6d/ospf6_top.c | 6 ++++++ ospf6d/ospf6_top.h | 1 + 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 57b7348bcc..0651b3188c 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -1985,6 +1985,38 @@ DEFUN (no_auto_cost_reference_bandwidth, } +DEFUN (ospf6_write_multiplier, + ospf6_write_multiplier_cmd, + "write-multiplier (1-100)", + "Write multiplier\n" + "Maximum number of interface serviced per write\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, o); + uint32_t write_oi_count; + + write_oi_count = strtol(argv[1]->arg, NULL, 10); + if (write_oi_count < 1 || write_oi_count > 100) { + vty_out(vty, "write-multiplier value is invalid\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + o->write_oi_count = write_oi_count; + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_write_multiplier, + no_ospf6_write_multiplier_cmd, + "no write-multiplier (1-100)", + NO_STR + "Write multiplier\n" + "Maximum number of interface serviced per write\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, o); + + o->write_oi_count = OSPF6_WRITE_INTERFACE_COUNT_DEFAULT; + return CMD_SUCCESS; +} + DEFUN (ipv6_ospf6_hellointerval, ipv6_ospf6_hellointerval_cmd, "ipv6 ospf6 hello-interval (1-65535)", @@ -2657,6 +2689,9 @@ void ospf6_interface_init(void) /* reference bandwidth commands */ install_element(OSPF6_NODE, &auto_cost_reference_bandwidth_cmd); install_element(OSPF6_NODE, &no_auto_cost_reference_bandwidth_cmd); + /* write-multiplier commands */ + install_element(OSPF6_NODE, &ospf6_write_multiplier_cmd); + install_element(OSPF6_NODE, &no_ospf6_write_multiplier_cmd); } /* Clear the specified interface structure */ diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 95ea4b5c14..a5470917e5 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1848,7 +1848,7 @@ int ospf6_receive(struct thread *thread) thread_add_read(master, ospf6_receive, ospf6, ospf6->fd, &ospf6->t_ospf6_receive); - while (count < OSPF6_WRITE_INTERFACE_COUNT_DEFAULT) { + while (count < ospf6->write_oi_count) { count++; switch (ospf6_read_helper(sockfd, ospf6)) { case OSPF6_READ_ERROR: @@ -1966,7 +1966,7 @@ static int ospf6_write(struct thread *thread) assert(node); oi = listgetdata(node); - while ((pkt_count < OSPF6_WRITE_INTERFACE_COUNT_DEFAULT) && oi + while ((pkt_count < ospf6->write_oi_count) && oi && (last_serviced_oi != oi)) { op = ospf6_fifo_head(oi->obuf); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index adfedcc49c..193ee4800d 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -406,6 +406,7 @@ static struct ospf6 *ospf6_create(const char *name) o->external_id_table = route_table_init(); + o->write_oi_count = OSPF6_WRITE_INTERFACE_COUNT_DEFAULT; o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; o->distance_table = route_table_init(); @@ -1668,6 +1669,11 @@ static int config_write_ospf6(struct vty *vty) vty_out(vty, " auto-cost reference-bandwidth %d\n", ospf6->ref_bandwidth); + if (ospf6->write_oi_count + != OSPF6_WRITE_INTERFACE_COUNT_DEFAULT) + vty_out(vty, " write-multiplier %d\n", + ospf6->write_oi_count); + /* LSA timers print. */ if (ospf6->lsa_minarrival != OSPF_MIN_LS_ARRIVAL) vty_out(vty, " timers lsa min-arrival %d\n", diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index dfd6893983..5b739ac76b 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -131,6 +131,7 @@ struct ospf6 { #define OSPF6_WRITE_INTERFACE_COUNT_DEFAULT 20 struct thread *t_write; + int write_oi_count; /* Num of packets sent per thread invocation */ uint32_t ref_bandwidth; /* Distance parameters */ From 44db98df2a4966cac9874714871682cf35ae5c4c Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Thu, 6 May 2021 12:59:52 +0100 Subject: [PATCH 12/13] doc: add OSPF[6] write-multiplier to docs Add documentation for write-muliplier to both OSPF and OSPF6 docs Signed-off-by: Pat Ruddy --- doc/user/ospf6d.rst | 7 +++++++ doc/user/ospfd.rst | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index d26062e2b9..7c01b6f136 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -70,6 +70,13 @@ OSPF6 router Use this command to control the maximum number of parallel routes that OSPFv3 can support. The default is 64. +.. clicmd:: write-multiplier (1-100) + + Use this command to tune the amount of work done in the packet read and + write threads before relinquishing control. The parameter is the number + of packets to process before returning. The default value of this parameter + is 20. + .. _ospf6-area: diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 80ab279596..692ce8c1b2 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -299,6 +299,13 @@ To start OSPF process you have to specify the OSPF router. a specific destination. The upper limit may differ if you change the value of MULTIPATH_NUM during compilation. The default is MULTIPATH_NUM (64). +.. clicmd:: write-multiplier (1-100) + + Use this command to tune the amount of work done in the packet read and + write threads before relinquishing control. The parameter is the number + of packets to process before returning. The defult value of this parameter + is 20. + .. _ospf-area: Areas From d01673b4cd27c36cc3fc8f27b383b80820bdff5c Mon Sep 17 00:00:00 2001 From: Pat Ruddy Date: Tue, 25 May 2021 10:39:03 +0100 Subject: [PATCH 13/13] tests: Modify topotests to include write-multiplier config Modify both the default and vrf ospf6 topologies to include a test where write-multiplier is configured to a non-default value and the ospf6 neighbors are reset then checked. Run black on both test files. Signed-off-by: Pat Ruddy --- .../topotests/ospf6_topo1/test_ospf6_topo1.py | 30 +++++++++++ .../ospf6_topo1_vrf/test_ospf6_topo1_vrf.py | 52 +++++++++++++++---- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/tests/topotests/ospf6_topo1/test_ospf6_topo1.py b/tests/topotests/ospf6_topo1/test_ospf6_topo1.py index f8c3476e18..bbd18a57ff 100644 --- a/tests/topotests/ospf6_topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6_topo1/test_ospf6_topo1.py @@ -360,6 +360,36 @@ def test_linux_ipv6_kernel_routingTable(): ) +def test_ospfv3_routingTable_write_multiplier(): + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + # For debugging, uncomment the next line + # tgen.mininet_cli() + + # Modify R1 write muliplier and reset the interfaces + r1 = tgen.gears["r1"] + + r1.vtysh_cmd("conf t\nrouter ospf6\n write-multiplier 100") + r1.vtysh_cmd("clear ipv6 ospf interface r1-stubnet") + r1.vtysh_cmd("clear ipv6 ospf interface r1-sw5") + + # Verify OSPFv3 Routing Table + for router, rnode in tgen.routers().items(): + logger.info('Waiting for router "%s" convergence', router) + + # Load expected results from the command + reffile = os.path.join(CWD, "{}/show_ipv6_route.ref".format(router)) + expected = open(reffile).read() + + # Run test function until we get an result. Wait at most 60 seconds. + test_func = partial(compare_show_ipv6, router, expected) + result, diff = topotest.run_and_expect(test_func, "", count=120, wait=0.5) + assert result, "OSPFv3 did not converge on {}:\n{}".format(router, diff) + + def test_shutdown_check_stderr(): tgen = get_topogen() diff --git a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py index e1857abc4f..b158099d9a 100755 --- a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py +++ b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py @@ -5,7 +5,7 @@ # Part of NetDEF Topology Tests # # Copyright (c) 2021 by Niral Networks, Inc. ("Niral Networks") -# Used Copyright (c) 2016 by Network Device Education Foundation, +# Used Copyright (c) 2016 by Network Device Education Foundation, # Inc. ("NetDEF") in this file. # # Permission to use, copy, modify, and/or distribute this software @@ -179,13 +179,9 @@ def setup_module(mod): "ip link set {0}-stubnet master {0}-cust1", ] - cmds1 = [ - "ip link set {0}-sw5 master {0}-cust1", - ] + cmds1 = ["ip link set {0}-sw5 master {0}-cust1"] - cmds2 = [ - "ip link set {0}-sw6 master {0}-cust1", - ] + cmds2 = ["ip link set {0}-sw6 master {0}-cust1"] # For all registered routers, load the zebra configuration file for rname, router in tgen.routers().items(): @@ -219,6 +215,7 @@ def teardown_module(mod): tgen = get_topogen() tgen.stop_topology() + def test_wait_protocol_convergence(): "Wait for OSPFv3 to converge" tgen = get_topogen() @@ -261,7 +258,7 @@ def compare_show_ipv6_vrf(rname, expected): # Use the vtysh output, with some masking to make comparison easy vrf_name = "{0}-cust1".format(rname) current = topotest.ip6_route_zebra(tgen.gears[rname], vrf_name) - + # Use just the 'O'spf lines of the output linearr = [] for line in current.splitlines(): @@ -331,7 +328,11 @@ def test_linux_ipv6_kernel_routingTable(): for i in range(1, 5): # Actual output from router - actual = tgen.gears["r{}".format(i)].run("ip -6 route show vrf r{}-cust1".format(i)).rstrip() + actual = ( + tgen.gears["r{}".format(i)] + .run("ip -6 route show vrf r{}-cust1".format(i)) + .rstrip() + ) if "nhid" in actual: refTableFile = os.path.join(CWD, "r{}/ip_6_address.nhg.ref".format(i)) else: @@ -362,9 +363,9 @@ def test_linux_ipv6_kernel_routingTable(): "unreachable fe80::/64 " ): continue - if 'anycast' in line: + if "anycast" in line: continue - if 'multicast' in line: + if "multicast" in line: continue filtered_lines.append(line) actual = "\n".join(filtered_lines).splitlines(1) @@ -398,6 +399,35 @@ def test_linux_ipv6_kernel_routingTable(): ) +def test_ospfv3_routingTable_write_multiplier(): + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + # For debugging, uncomment the next line + # tgen.mininet_cli() + # Modify R1 write muliplier and reset the interfaces + r1 = tgen.gears["r1"] + + r1.vtysh_cmd("conf t\nrouter ospf6 vrf r1-cust1 \n write-multiplier 100") + r1.vtysh_cmd("clear ipv6 ospf interface r1-stubnet") + r1.vtysh_cmd("clear ipv6 ospf interface r1-sw5") + + # Verify OSPFv3 Routing Table + for router, rnode in tgen.routers().iteritems(): + logger.info('Waiting for router "%s" convergence', router) + + # Load expected results from the command + reffile = os.path.join(CWD, "{}/show_ipv6_vrf_route.ref".format(router)) + expected = open(reffile).read() + + # Run test function until we get an result. Wait at most 60 seconds. + test_func = partial(compare_show_ipv6_vrf, router, expected) + result, diff = topotest.run_and_expect(test_func, "", count=120, wait=0.5) + assert result, "OSPFv3 did not converge on {}:\n{}".format(router, diff) + + def test_shutdown_check_stderr(): tgen = get_topogen()