ospfd: Allow packet reads based upon read/write packet counts

Read in up to 20(ospf write-multipler X) packets, for handling of data.

This improves performance because we allow ospf to have a bit more data
to work on in one go for spf calculations instead of 1 packet at a time.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
Donald Sharp 2019-11-06 23:04:32 -05:00
parent edca5860cb
commit 4392cc4337

View File

@ -2310,10 +2310,12 @@ static struct stream *ospf_recv_packet(struct ospf *ospf, int fd,
msgh.msg_control = (caddr_t)buff; msgh.msg_control = (caddr_t)buff;
msgh.msg_controllen = sizeof(buff); msgh.msg_controllen = sizeof(buff);
ret = stream_recvmsg(ibuf, fd, &msgh, 0, OSPF_MAX_PACKET_SIZE + 1); ret = stream_recvmsg(ibuf, fd, &msgh, MSG_DONTWAIT,
OSPF_MAX_PACKET_SIZE + 1);
if (ret < 0) { if (ret < 0) {
flog_warn(EC_OSPF_PACKET, "stream_recvmsg failed: %s", if (errno != EAGAIN && errno != EWOULDBLOCK)
safe_strerror(errno)); flog_warn(EC_OSPF_PACKET, "stream_recvmsg failed: %s",
safe_strerror(errno));
return NULL; return NULL;
} }
if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */ if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */
@ -2947,228 +2949,248 @@ int ospf_read(struct thread *thread)
uint16_t length; uint16_t length;
struct interface *ifp = NULL; struct interface *ifp = NULL;
struct connected *c; struct connected *c;
int32_t count = 0;
/* first of all get interface pointer. */ /* first of all get interface pointer. */
ospf = THREAD_ARG(thread); ospf = THREAD_ARG(thread);
/* prepare for next packet. */ /* prepare for next packet. */
ospf->t_read = NULL;
thread_add_read(master, ospf_read, ospf, ospf->fd, &ospf->t_read); thread_add_read(master, ospf_read, ospf, ospf->fd, &ospf->t_read);
stream_reset(ospf->ibuf); while (count < ospf->write_oi_count) {
ibuf = ospf_recv_packet(ospf, ospf->fd, &ifp, ospf->ibuf); count++;
if (ibuf == NULL) stream_reset(ospf->ibuf);
return -1; ibuf = ospf_recv_packet(ospf, ospf->fd, &ifp, ospf->ibuf);
/* This raw packet is known to be at least as big as its IP header. */ if (ibuf == NULL)
return -1;
/*
* This raw packet is known to be at least as big as its
* IP header.
* Note that there should not be alignment problems with
* this assignment because this is at the beginning of the
* stream data buffer.
*/
iph = (struct ip *)STREAM_DATA(ibuf);
/* Note that sockopt_iphdrincl_swab_systoh was called in
* ospf_recv_packet. */
/* Note that there should not be alignment problems with this assignment
because this is at the beginning of the stream data buffer. */
iph = (struct ip *)STREAM_DATA(ibuf);
/* Note that sockopt_iphdrincl_swab_systoh was called in
* ospf_recv_packet. */
if (ifp == NULL) {
/* Handle cases where the platform does not support retrieving
the ifindex,
and also platforms (such as Solaris 8) that claim to support
ifindex
retrieval but do not. */
c = if_lookup_address((void *)&iph->ip_src, AF_INET,
ospf->vrf_id);
if (c)
ifp = c->ifp;
if (ifp == NULL) { if (ifp == NULL) {
if (IS_DEBUG_OSPF_PACKET(0, RECV)) /* Handle cases where the platform does not support
* retrieving the ifindex, and also platforms (such
* as Solaris 8) that claim to support ifindex
* retrieval but do not.
*/
c = if_lookup_address((void *)&iph->ip_src, AF_INET,
ospf->vrf_id);
if (c)
ifp = c->ifp;
if (ifp == NULL) {
if (IS_DEBUG_OSPF_PACKET(0, RECV))
zlog_debug(
"%s: Unable to determine incoming interface from: %s(%s)",
__PRETTY_FUNCTION__,
inet_ntoa(iph->ip_src),
ospf_get_name(ospf));
continue;
}
}
/* Self-originated packet should be discarded silently. */
if (ospf_if_lookup_by_local_addr(ospf, NULL, iph->ip_src)) {
if (IS_DEBUG_OSPF_PACKET(0, RECV)) {
zlog_debug( zlog_debug(
"%s: Unable to determine incoming interface from: %s(%s)", "ospf_read[%s]: Dropping self-originated packet",
__PRETTY_FUNCTION__, inet_ntoa(iph->ip_src));
inet_ntoa(iph->ip_src), }
ospf_get_name(ospf)); continue;
return 0;
} }
}
/* Self-originated packet should be discarded silently. */ /*
if (ospf_if_lookup_by_local_addr(ospf, NULL, iph->ip_src)) { * Advance from IP header to OSPF header (iph->ip_hl has
if (IS_DEBUG_OSPF_PACKET(0, RECV)) { * been verified by ospf_recv_packet() to be correct).
zlog_debug( */
"ospf_read[%s]: Dropping self-originated packet", stream_forward_getp(ibuf, iph->ip_hl * 4);
inet_ntoa(iph->ip_src));
ospfh = (struct ospf_header *)stream_pnt(ibuf);
if (MSG_OK
!= ospf_packet_examin(ospfh,
stream_get_endp(ibuf)
- stream_get_getp(ibuf)))
continue;
/* Now it is safe to access all fields of OSPF packet header. */
/* associate packet with ospf interface */
oi = ospf_if_lookup_recv_if(ospf, iph->ip_src, ifp);
/* ospf_verify_header() relies on a valid "oi" and thus can
* be called only after the passive/backbone/other checks
* below are passed. These checks in turn access the fields
* of unverified "ospfh" structure for their own purposes and
* must remain very accurate in doing this. */
/* If incoming interface is passive one, ignore it. */
if (oi && OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_PASSIVE) {
char buf[3][INET_ADDRSTRLEN];
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
"ignoring packet from router %s sent to %s, "
"received on a passive interface, %s",
inet_ntop(AF_INET, &ospfh->router_id,
buf[0], sizeof(buf[0])),
inet_ntop(AF_INET, &iph->ip_dst, buf[1],
sizeof(buf[1])),
inet_ntop(AF_INET,
&oi->address->u.prefix4,
buf[2], sizeof(buf[2])));
if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS)) {
/* Try to fix multicast membership.
* Some OS:es may have problems in this area,
* make sure it is removed.
*/
OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS);
ospf_if_set_multicast(oi);
}
continue;
} }
return 0;
}
/* Advance from IP header to OSPF header (iph->ip_hl has been verified
by ospf_recv_packet() to be correct). */
stream_forward_getp(ibuf, iph->ip_hl * 4);
ospfh = (struct ospf_header *)stream_pnt(ibuf); /* if no local ospf_interface,
if (MSG_OK * or header area is backbone but ospf_interface is not
!= ospf_packet_examin( * check for VLINK interface
ospfh, stream_get_endp(ibuf) - stream_get_getp(ibuf))) */
return -1; if ((oi == NULL)
/* Now it is safe to access all fields of OSPF packet header. */ || (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id)
&& !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id))) {
if ((oi = ospf_associate_packet_vl(ospf, ifp, iph,
ospfh))
== NULL) {
if (!ospf->instance && IS_DEBUG_OSPF_EVENT)
zlog_debug(
"Packet from [%s] received on link %s"
" but no ospf_interface",
inet_ntoa(iph->ip_src),
ifp->name);
return 0;
}
}
/* associate packet with ospf interface */ /*
oi = ospf_if_lookup_recv_if(ospf, iph->ip_src, ifp); * else it must be a local ospf interface, check it was
* received on correct link
*/
else if (oi->ifp != ifp) {
if (IS_DEBUG_OSPF_EVENT)
flog_warn(
EC_OSPF_PACKET,
"Packet from [%s] received on wrong link %s",
inet_ntoa(iph->ip_src), ifp->name);
continue;
} else if (oi->state == ISM_Down) {
char buf[2][INET_ADDRSTRLEN];
/* ospf_verify_header() relies on a valid "oi" and thus can be called flog_warn(
only EC_OSPF_PACKET,
after the passive/backbone/other checks below are passed. These "Ignoring packet from %s to %s received on interface that is "
checks "down [%s]; interface flags are %s",
in turn access the fields of unverified "ospfh" structure for their inet_ntop(AF_INET, &iph->ip_src, buf[0],
own
purposes and must remain very accurate in doing this. */
/* If incoming interface is passive one, ignore it. */
if (oi && OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_PASSIVE) {
char buf[3][INET_ADDRSTRLEN];
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
"ignoring packet from router %s sent to %s, "
"received on a passive interface, %s",
inet_ntop(AF_INET, &ospfh->router_id, buf[0],
sizeof(buf[0])), sizeof(buf[0])),
inet_ntop(AF_INET, &iph->ip_dst, buf[1], inet_ntop(AF_INET, &iph->ip_dst, buf[1],
sizeof(buf[1])), sizeof(buf[1])),
inet_ntop(AF_INET, &oi->address->u.prefix4, ifp->name, if_flag_dump(ifp->flags));
buf[2], sizeof(buf[2]))); /* Fix multicast memberships? */
if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS))
if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS)) { OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS);
/* Try to fix multicast membership. else if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS))
* Some OS:es may have problems in this area, OI_MEMBER_JOINED(oi, MEMBER_DROUTERS);
* make sure it is removed. if (oi->multicast_memberships)
*/ ospf_if_set_multicast(oi);
OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS); continue;
ospf_if_set_multicast(oi);
} }
return 0;
}
/*
* If the received packet is destined for AllDRouters, the
* packet should be accepted only if the received ospf
* interface state is either DR or Backup -- endo.
*
* I wonder who endo is?
*/
if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS)
&& (oi->state != ISM_DR && oi->state != ISM_Backup)) {
flog_warn(
EC_OSPF_PACKET,
"Dropping packet for AllDRouters from [%s] via [%s] (ISM: %s)",
inet_ntoa(iph->ip_src), IF_NAME(oi),
lookup_msg(ospf_ism_state_msg, oi->state,
NULL));
/* Try to fix multicast membership. */
SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
ospf_if_set_multicast(oi);
continue;
}
/* if no local ospf_interface, /* Verify more OSPF header fields. */
* or header area is backbone but ospf_interface is not ret = ospf_verify_header(ibuf, oi, iph, ospfh);
* check for VLINK interface if (ret < 0) {
*/ if (IS_DEBUG_OSPF_PACKET(0, RECV))
if ((oi == NULL) || (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id)
&& !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id))) {
if ((oi = ospf_associate_packet_vl(ospf, ifp, iph, ospfh))
== NULL) {
if (!ospf->instance && IS_DEBUG_OSPF_EVENT)
zlog_debug( zlog_debug(
"Packet from [%s] received on link %s" "ospf_read[%s]: Header check failed, "
" but no ospf_interface", "dropping.",
inet_ntoa(iph->ip_src), ifp->name); inet_ntoa(iph->ip_src));
return 0; continue;
}
}
/* else it must be a local ospf interface, check it was received on
* correct link
*/
else if (oi->ifp != ifp) {
if (IS_DEBUG_OSPF_EVENT)
flog_warn(EC_OSPF_PACKET,
"Packet from [%s] received on wrong link %s",
inet_ntoa(iph->ip_src), ifp->name);
return 0;
} else if (oi->state == ISM_Down) {
char buf[2][INET_ADDRSTRLEN];
flog_warn(
EC_OSPF_PACKET,
"Ignoring packet from %s to %s received on interface that is "
"down [%s]; interface flags are %s",
inet_ntop(AF_INET, &iph->ip_src, buf[0],
sizeof(buf[0])),
inet_ntop(AF_INET, &iph->ip_dst, buf[1],
sizeof(buf[1])),
ifp->name, if_flag_dump(ifp->flags));
/* Fix multicast memberships? */
if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS))
OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS);
else if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS))
OI_MEMBER_JOINED(oi, MEMBER_DROUTERS);
if (oi->multicast_memberships)
ospf_if_set_multicast(oi);
return 0;
}
/*
* If the received packet is destined for AllDRouters, the packet
* should be accepted only if the received ospf interface state is
* either DR or Backup -- endo.
*/
if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS)
&& (oi->state != ISM_DR && oi->state != ISM_Backup)) {
flog_warn(
EC_OSPF_PACKET,
"Dropping packet for AllDRouters from [%s] via [%s] (ISM: %s)",
inet_ntoa(iph->ip_src), IF_NAME(oi),
lookup_msg(ospf_ism_state_msg, oi->state, NULL));
/* Try to fix multicast membership. */
SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
ospf_if_set_multicast(oi);
return 0;
}
/* Verify more OSPF header fields. */
ret = ospf_verify_header(ibuf, oi, iph, ospfh);
if (ret < 0) {
if (IS_DEBUG_OSPF_PACKET(0, RECV))
zlog_debug(
"ospf_read[%s]: Header check failed, "
"dropping.",
inet_ntoa(iph->ip_src));
return ret;
}
/* Show debug receiving packet. */
if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) {
if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, DETAIL)) {
zlog_debug(
"-----------------------------------------------------");
ospf_packet_dump(ibuf);
} }
zlog_debug("%s received from [%s] via [%s]", /* Show debug receiving packet. */
lookup_msg(ospf_packet_type_str, ospfh->type, NULL), if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) {
inet_ntoa(ospfh->router_id), IF_NAME(oi)); if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, DETAIL)) {
zlog_debug(" src [%s],", inet_ntoa(iph->ip_src)); zlog_debug(
zlog_debug(" dst [%s]", inet_ntoa(iph->ip_dst)); "-----------------------------------------------------");
ospf_packet_dump(ibuf);
}
if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, DETAIL)) zlog_debug("%s received from [%s] via [%s]",
zlog_debug( lookup_msg(ospf_packet_type_str, ospfh->type,
"-----------------------------------------------------"); NULL),
} inet_ntoa(ospfh->router_id), IF_NAME(oi));
zlog_debug(" src [%s],", inet_ntoa(iph->ip_src));
zlog_debug(" dst [%s]", inet_ntoa(iph->ip_dst));
stream_forward_getp(ibuf, OSPF_HEADER_SIZE); if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, DETAIL))
zlog_debug(
"-----------------------------------------------------");
}
/* Adjust size to message length. */ stream_forward_getp(ibuf, OSPF_HEADER_SIZE);
length = ntohs(ospfh->length) - OSPF_HEADER_SIZE;
/* Read rest of the packet and call each sort of packet routine. */ /* Adjust size to message length. */
switch (ospfh->type) { length = ntohs(ospfh->length) - OSPF_HEADER_SIZE;
case OSPF_MSG_HELLO:
ospf_hello(iph, ospfh, ibuf, oi, length); /* Read rest of the packet and call each sort of packet routine.
break; */
case OSPF_MSG_DB_DESC: switch (ospfh->type) {
ospf_db_desc(iph, ospfh, ibuf, oi, length); case OSPF_MSG_HELLO:
break; ospf_hello(iph, ospfh, ibuf, oi, length);
case OSPF_MSG_LS_REQ: break;
ospf_ls_req(iph, ospfh, ibuf, oi, length); case OSPF_MSG_DB_DESC:
break; ospf_db_desc(iph, ospfh, ibuf, oi, length);
case OSPF_MSG_LS_UPD: break;
ospf_ls_upd(ospf, iph, ospfh, ibuf, oi, length); case OSPF_MSG_LS_REQ:
break; ospf_ls_req(iph, ospfh, ibuf, oi, length);
case OSPF_MSG_LS_ACK: break;
ospf_ls_ack(iph, ospfh, ibuf, oi, length); case OSPF_MSG_LS_UPD:
break; ospf_ls_upd(ospf, iph, ospfh, ibuf, oi, length);
default: break;
flog_warn(EC_OSPF_PACKET, case OSPF_MSG_LS_ACK:
"interface %s: OSPF packet header type %d is illegal", ospf_ls_ack(iph, ospfh, ibuf, oi, length);
IF_NAME(oi), ospfh->type); break;
break; default:
flog_warn(
EC_OSPF_PACKET,
"interface %s(%s): OSPF packet header type %d is illegal",
IF_NAME(oi), ospf_get_name(ospf), ospfh->type);
break;
}
} }
return 0; return 0;