From 2f8f370e356c485c57ec3522f797c96610abf44e Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 19 May 2015 17:24:42 -0700 Subject: [PATCH] In the "write" direction added a command to ensure that Quagga is able to send out K (=3 by default) packets per thread-write. Signed-off-by: Ayan Banerjee Reviewed-by: JR Rivers --- ospfd/ospf_packet.c | 218 +++++++++++++++++++++++--------------------- ospfd/ospf_vty.c | 44 +++++++++ ospfd/ospfd.c | 1 + ospfd/ospfd.h | 2 + 4 files changed, 162 insertions(+), 103 deletions(-) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index c0c0924377..43a237cf55 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -217,6 +217,13 @@ ospf_fifo_flush (struct ospf_fifo *fifo) fifo->count = 0; } +/* Return the current fifo count */ +static int +ospf_fifo_count (struct ospf_fifo *fifo) +{ + return (fifo->count); +} + /* Free ospf packet fifo. */ void ospf_fifo_free (struct ospf_fifo *fifo) @@ -647,6 +654,7 @@ ospf_write (struct thread *thread) #endif /* WANT_OSPF_WRITE_FRAGMENT */ u_int16_t maxdatasize; #define OSPF_WRITE_IPHL_SHIFT 2 + int pkt_count = 0; ospf->t_write = NULL; @@ -668,131 +676,135 @@ ospf_write (struct thread *thread) maxdatasize = MIN (oi->ifp->mtu, ospf->maxsndbuflen) - sizeof (struct ip); - /* Get one packet from queue. */ - op = ospf_fifo_head (oi->obuf); - assert (op); - assert (op->length >= OSPF_HEADER_SIZE); - - if (op->dst.s_addr == htonl (OSPF_ALLSPFROUTERS) - || op->dst.s_addr == htonl (OSPF_ALLDROUTERS)) - ospf_if_ipmulticast (ospf, oi->address, oi->ifp->ifindex); - - /* Rewrite the md5 signature & update the seq */ - ospf_make_md5_digest (oi, op); - - /* Retrieve OSPF packet type. */ - stream_set_getp (op->s, 1); - type = stream_getc (op->s); + while ((pkt_count < ospf->write_multiplier) && ospf_fifo_count(oi->obuf)) + { + pkt_count++; + /* Get one packet from queue. */ + op = ospf_fifo_head (oi->obuf); + assert (op); + assert (op->length >= OSPF_HEADER_SIZE); + + if (op->dst.s_addr == htonl (OSPF_ALLSPFROUTERS) + || op->dst.s_addr == htonl (OSPF_ALLDROUTERS)) + ospf_if_ipmulticast (ospf, oi->address, oi->ifp->ifindex); + + /* Rewrite the md5 signature & update the seq */ + ospf_make_md5_digest (oi, op); + + /* Retrieve OSPF packet type. */ + stream_set_getp (op->s, 1); + type = stream_getc (op->s); - /* reset get pointer */ - stream_set_getp (op->s, 0); + /* reset get pointer */ + stream_set_getp (op->s, 0); - memset (&iph, 0, sizeof (struct ip)); - memset (&sa_dst, 0, sizeof (sa_dst)); + memset (&iph, 0, sizeof (struct ip)); + memset (&sa_dst, 0, sizeof (sa_dst)); - sa_dst.sin_family = AF_INET; + sa_dst.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sa_dst.sin_len = sizeof(sa_dst); + sa_dst.sin_len = sizeof(sa_dst); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - sa_dst.sin_addr = op->dst; - sa_dst.sin_port = htons (0); - - /* Set DONTROUTE flag if dst is unicast. */ - if (oi->type != OSPF_IFTYPE_VIRTUALLINK) - if (!IN_MULTICAST (htonl (op->dst.s_addr))) - flags = MSG_DONTROUTE; - - iph.ip_hl = sizeof (struct ip) >> OSPF_WRITE_IPHL_SHIFT; - /* it'd be very strange for header to not be 4byte-word aligned but.. */ - if ( sizeof (struct ip) - > (unsigned int)(iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) ) - iph.ip_hl++; /* we presume sizeof struct ip cant overflow ip_hl.. */ + sa_dst.sin_addr = op->dst; + sa_dst.sin_port = htons (0); + + /* Set DONTROUTE flag if dst is unicast. */ + if (oi->type != OSPF_IFTYPE_VIRTUALLINK) + if (!IN_MULTICAST (htonl (op->dst.s_addr))) + flags = MSG_DONTROUTE; + + iph.ip_hl = sizeof (struct ip) >> OSPF_WRITE_IPHL_SHIFT; + /* it'd be very strange for header to not be 4byte-word aligned but.. */ + if ( sizeof (struct ip) + > (unsigned int)(iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) ) + iph.ip_hl++; /* we presume sizeof struct ip cant overflow ip_hl.. */ - iph.ip_v = IPVERSION; - iph.ip_tos = IPTOS_PREC_INTERNETCONTROL; - iph.ip_len = (iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) + op->length; + iph.ip_v = IPVERSION; + iph.ip_tos = IPTOS_PREC_INTERNETCONTROL; + iph.ip_len = (iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) + op->length; #if defined(__DragonFly__) - /* - * DragonFly's raw socket expects ip_len/ip_off in network byte order. - */ - iph.ip_len = htons(iph.ip_len); + /* + * DragonFly's raw socket expects ip_len/ip_off in network byte order. + */ + iph.ip_len = htons(iph.ip_len); #endif #ifdef WANT_OSPF_WRITE_FRAGMENT - /* XXX-MT: not thread-safe at all.. - * XXX: this presumes this is only programme sending OSPF packets - * otherwise, no guarantee ipid will be unique - */ - iph.ip_id = ++ipid; + /* XXX-MT: not thread-safe at all.. + * XXX: this presumes this is only programme sending OSPF packets + * otherwise, no guarantee ipid will be unique + */ + iph.ip_id = ++ipid; #endif /* WANT_OSPF_WRITE_FRAGMENT */ - iph.ip_off = 0; - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) - iph.ip_ttl = OSPF_VL_IP_TTL; - else - iph.ip_ttl = OSPF_IP_TTL; - iph.ip_p = IPPROTO_OSPFIGP; - iph.ip_sum = 0; - iph.ip_src.s_addr = oi->address->u.prefix4.s_addr; - iph.ip_dst.s_addr = op->dst.s_addr; - - memset (&msg, 0, sizeof (msg)); - msg.msg_name = (caddr_t) &sa_dst; - msg.msg_namelen = sizeof (sa_dst); - msg.msg_iov = iov; - msg.msg_iovlen = 2; - iov[0].iov_base = (char*)&iph; - iov[0].iov_len = iph.ip_hl << OSPF_WRITE_IPHL_SHIFT; - iov[1].iov_base = STREAM_PNT (op->s); - iov[1].iov_len = op->length; + iph.ip_off = 0; + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + iph.ip_ttl = OSPF_VL_IP_TTL; + else + iph.ip_ttl = OSPF_IP_TTL; + iph.ip_p = IPPROTO_OSPFIGP; + iph.ip_sum = 0; + iph.ip_src.s_addr = oi->address->u.prefix4.s_addr; + iph.ip_dst.s_addr = op->dst.s_addr; + + memset (&msg, 0, sizeof (msg)); + msg.msg_name = (caddr_t) &sa_dst; + msg.msg_namelen = sizeof (sa_dst); + msg.msg_iov = iov; + msg.msg_iovlen = 2; + iov[0].iov_base = (char*)&iph; + iov[0].iov_len = iph.ip_hl << OSPF_WRITE_IPHL_SHIFT; + iov[1].iov_base = STREAM_PNT (op->s); + iov[1].iov_len = op->length; - /* Sadly we can not rely on kernels to fragment packets because of either - * IP_HDRINCL and/or multicast destination being set. - */ + /* Sadly we can not rely on kernels to fragment packets because of either + * IP_HDRINCL and/or multicast destination being set. + */ #ifdef WANT_OSPF_WRITE_FRAGMENT - if ( op->length > maxdatasize ) - ospf_write_frags (ospf->fd, op, &iph, &msg, maxdatasize, - oi->ifp->mtu, flags, type); + if ( op->length > maxdatasize ) + ospf_write_frags (ospf->fd, op, &iph, &msg, maxdatasize, + oi->ifp->mtu, flags, type); #endif /* WANT_OSPF_WRITE_FRAGMENT */ - /* send final fragment (could be first) */ - sockopt_iphdrincl_swab_htosys (&iph); - ret = sendmsg (ospf->fd, &msg, flags); - sockopt_iphdrincl_swab_systoh (&iph); - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_write to %s, " - "id %d, off %d, len %d, interface %s, mtu %u:", - inet_ntoa (iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len, - oi->ifp->name, oi->ifp->mtu); + /* send final fragment (could be first) */ + sockopt_iphdrincl_swab_htosys (&iph); + ret = sendmsg (ospf->fd, &msg, flags); + sockopt_iphdrincl_swab_systoh (&iph); + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("ospf_write to %s, " + "id %d, off %d, len %d, interface %s, mtu %u:", + inet_ntoa (iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len, + oi->ifp->name, oi->ifp->mtu); - if (ret < 0) - zlog_warn ("*** sendmsg in ospf_write failed to %s, " - "id %d, off %d, len %d, interface %s, mtu %u: %s", - inet_ntoa (iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len, - oi->ifp->name, oi->ifp->mtu, safe_strerror (errno)); + if (ret < 0) + zlog_warn ("*** sendmsg in ospf_write failed to %s, " + "id %d, off %d, len %d, interface %s, mtu %u: %s", + inet_ntoa (iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len, + oi->ifp->name, oi->ifp->mtu, safe_strerror (errno)); - /* Show debug sending packet. */ - if (IS_DEBUG_OSPF_PACKET (type - 1, SEND)) - { - if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) - { - zlog_debug ("-----------------------------------------------------"); - ospf_ip_header_dump (&iph); - stream_set_getp (op->s, 0); - ospf_packet_dump (op->s); - } + /* Show debug sending packet. */ + if (IS_DEBUG_OSPF_PACKET (type - 1, SEND)) + { + if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) + { + zlog_debug ("-----------------------------------------------------"); + ospf_ip_header_dump (&iph); + stream_set_getp (op->s, 0); + ospf_packet_dump (op->s); + } - zlog_debug ("%s sent to [%s] via [%s].", - LOOKUP (ospf_packet_type_str, type), inet_ntoa (op->dst), - IF_NAME (oi)); + zlog_debug ("%s sent to [%s] via [%s].", + LOOKUP (ospf_packet_type_str, type), inet_ntoa (op->dst), + IF_NAME (oi)); - if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) - zlog_debug ("-----------------------------------------------------"); - } + if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) + zlog_debug ("-----------------------------------------------------"); + } - /* Now delete packet from queue. */ - ospf_packet_delete (oi); + /* Now delete packet from queue. */ + ospf_packet_delete (oi); + } /* Move this interface to the tail of write_q to serve everyone in a round robin fashion */ diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 561d811499..b9c99b1dbd 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2531,6 +2531,37 @@ DEFUN (no_ospf_auto_cost_reference_bandwidth, return CMD_SUCCESS; } +DEFUN (ospf_write_multiplier, + ospf_write_multiplier_cmd, + "write-multiplier <1-50>", + "Number of writes per thread callback\n") +{ + struct ospf *ospf = vty->index; + u_int32_t write_multiplier; + + write_multiplier = strtol (argv[0], NULL, 10); + if (write_multiplier < 1 || write_multiplier > 50) + { + vty_out (vty, "write-multiplier value is invalid%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ospf->write_multiplier = write_multiplier; + return CMD_SUCCESS; +} + +DEFUN (no_ospf_write_multiplier, + no_ospf_write_multiplier_cmd, + "no write-multiplier", + NO_STR + "Number of writes per thread callback\n") +{ + struct ospf *ospf = vty->index; + + ospf->write_multiplier = OSPF_WRITE_MULTIPLIER_DEFAULT; + return CMD_SUCCESS; +} + const char *ospf_abr_type_descr_str[] = { "Unknown", @@ -2760,6 +2791,10 @@ DEFUN (show_ip_ospf, ospf_timer_dump (ospf->t_spf_calc, timebuf, sizeof (timebuf)), VTY_NEWLINE); + /* Show write multiplier values */ + vty_out (vty, " Write Multiplier set to %d %s", + ospf->write_multiplier, VTY_NEWLINE); + /* Show refresh parameters. */ vty_out (vty, " Refresh timer %d secs%s", ospf->lsa_refresh_interval, VTY_NEWLINE); @@ -7287,6 +7322,11 @@ ospf_config_write (struct vty *vty) ospf->spf_delay, ospf->spf_holdtime, ospf->spf_max_holdtime, VTY_NEWLINE); + /* Write multiplier print. */ + if (ospf->write_multiplier != OSPF_WRITE_MULTIPLIER_DEFAULT) + vty_out (vty, " ospf write-multiplier %d%s", + ospf->write_multiplier, VTY_NEWLINE); + /* Max-metric router-lsa print */ config_write_stub_router (vty, ospf); @@ -7723,6 +7763,10 @@ ospf_vty_init (void) install_element (OSPF_NODE, &no_ospf_neighbor_priority_cmd); install_element (OSPF_NODE, &no_ospf_neighbor_poll_interval_cmd); + /* write multiplier commands */ + install_element (OSPF_NODE, &ospf_write_multiplier_cmd); + install_element (OSPF_NODE, &no_ospf_write_multiplier_cmd); + /* Init interface related vty commands. */ ospf_vty_if_init (); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index dd57f645b7..09f3a14247 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -233,6 +233,7 @@ ospf_new (void) } new->t_read = thread_add_read (master, ospf_read, new, new->fd); new->oi_write_q = list_new (); + new->write_multiplier = OSPF_WRITE_MULTIPLIER_DEFAULT; return new; } diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index bf70d02275..3e8b52e9e3 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -219,6 +219,8 @@ struct ospf struct thread *t_deferred_shutdown; /* deferred/stub-router shutdown timer*/ struct thread *t_write; +#define OSPF_WRITE_MULTIPLIER_DEFAULT 3 + int write_multiplier; /* Num of packets sent per thread invocation */ struct thread *t_read; int fd; unsigned int maxsndbuflen; -- 2.39.5