diff options
Diffstat (limited to 'ospfd/ospf_packet.c')
-rw-r--r-- | ospfd/ospf_packet.c | 267 |
1 files changed, 153 insertions, 114 deletions
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 25f70bba..48fe0829 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -633,6 +633,7 @@ ospf_write (struct thread *thread) { struct ospf *ospf = THREAD_ARG (thread); struct ospf_interface *oi; + struct ospf_interface *last_serviced_oi = NULL; struct ospf_packet *op; struct sockaddr_in sa_dst; struct ip iph; @@ -647,6 +648,7 @@ ospf_write (struct thread *thread) u_int16_t maxdatasize; #endif /* WANT_OSPF_WRITE_FRAGMENT */ #define OSPF_WRITE_IPHL_SHIFT 2 + int pkt_count = 0; ospf->t_write = NULL; @@ -659,143 +661,173 @@ ospf_write (struct thread *thread) /* seed ipid static with low order bits of time */ if (ipid == 0) ipid = (time(NULL) & 0xffff); - - /* convenience - max OSPF data per packet, - * and reliability - not more data, than our - * socket can accept - */ - maxdatasize = MIN (oi->ifp->mtu, ospf->maxsndbuflen) - - sizeof (struct ip); #endif /* WANT_OSPF_WRITE_FRAGMENT */ - - /* 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_oi_count) && oi && (last_serviced_oi != oi)) + { + /* If there is only packet in the queue, the oi is removed from + write-q, so fix up the last interface that was serviced */ + if (last_serviced_oi == NULL) { + last_serviced_oi = oi; + } + pkt_count++; + /* convenience - max OSPF data per packet, + * and reliability - not more data, than our + * socket can accept + */ +#if defined (WANT_OSPF_WRITE_FRAGMENT) + maxdatasize = MIN (oi->ifp->mtu, ospf->maxsndbuflen) - + sizeof (struct ip); +#endif + + /* 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); + /* 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 + /* Move this interface to the tail of write_q to serve everyone in a round robin fashion */ - listnode_move_to_tail (ospf->oi_write_q, node); - if (ospf_fifo_head (oi->obuf) == NULL) - { - oi->on_write_q = 0; list_delete_node (ospf->oi_write_q, node); + if (ospf_fifo_head (oi->obuf) == NULL) + { + oi->on_write_q = 0; + last_serviced_oi = NULL; + oi = NULL; + } + else + { + listnode_add (ospf->oi_write_q, oi); + } + + /* Setup to service from the head of the queue again */ + if (!list_isempty (ospf->oi_write_q)) + { + node = listhead (ospf->oi_write_q); + assert (node); + oi = listgetdata (node); + assert (oi); + } } /* If packets still remain in queue, call write thread. */ @@ -1162,6 +1194,9 @@ ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi, /* Save received neighbor values from DD. */ ospf_db_desc_save_current (nbr, dd); + + if (!nbr->t_ls_req) + ospf_ls_req_send (nbr); } static int @@ -3022,7 +3057,8 @@ ospf_make_hello (struct ospf_interface *oi, struct stream *s) int flag = 0; /* Set netmask of interface. */ - if (oi->type != OSPF_IFTYPE_POINTOPOINT && + if (!(CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED) && + oi->type == OSPF_IFTYPE_POINTOPOINT) && oi->type != OSPF_IFTYPE_VIRTUALLINK) masklen2ip (oi->address->prefixlen, &mask); else @@ -3830,9 +3866,12 @@ ospf_ls_ack_send_list (struct ospf_interface *oi, struct list *ack, /* Set packet length. */ op->length = length; - /* Set destination IP address. */ - op->dst = dst; - + /* Decide destination address. */ + if (oi->type == OSPF_IFTYPE_POINTOPOINT) + op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS); + else + op->dst.s_addr = dst.s_addr; + /* Add packet to the interface output queue. */ ospf_packet_add (oi, op); |