I noticed that when starting my test bgpd multihop sessions that the session engine is busy spinning until the tables are loaded. Now since the network is rather slow this does not make sense and indicates that the poll timeout is wrongly set to 0 almost all the time until the session finished the initial load.
Looking at this I realized that the current indication that there is still work pending for a peer is wrong. Just checking if there is data in the read buffer is wrong since in my case this most probably because of a short read and so no immediate work needs to happen. This diff changes the check and replaces it with a flag that is only set in the case we stopped parsing because of hitting the MSG_PROCESS_LIMIT. With this my session engine no longer busy loops at start which saves a lot of CPU :) -- :wq Claudio Index: session.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/session.c,v retrieving revision 1.377 diff -u -p -r1.377 session.c --- session.c 31 Mar 2019 16:57:38 -0000 1.377 +++ session.c 2 Apr 2019 10:23:09 -0000 @@ -81,7 +81,7 @@ void session_rrefresh(struct peer *, u_i int session_graceful_restart(struct peer *); int session_graceful_stop(struct peer *); int session_dispatch_msg(struct pollfd *, struct peer *); -int session_process_msg(struct peer *); +void session_process_msg(struct peer *); int parse_header(struct peer *, u_char *, u_int16_t *, u_int8_t *); int parse_open(struct peer *); int parse_update(struct peer *); @@ -426,7 +426,7 @@ session_main(int debug, int verbose) if (p->wbuf.queued > 0 || p->state == STATE_CONNECT) events |= POLLOUT; /* is there still work to do? */ - if (p->rbuf && p->rbuf->wpos) + if (p->rpending) timeout = 0; /* poll events */ @@ -1779,7 +1779,7 @@ session_dispatch_msg(struct pollfd *pfd, return (0); } -int +void session_process_msg(struct peer *p) { struct mrt *mrt; @@ -1790,19 +1790,20 @@ session_process_msg(struct peer *p) rpos = 0; av = p->rbuf->wpos; + p->rpending = 0; /* * session might drop to IDLE -> buffers deallocated * we MUST check rbuf != NULL before use */ for (;;) { - if (rpos + MSGSIZE_HEADER > av) - break; if (p->rbuf == NULL) + return; + if (rpos + MSGSIZE_HEADER > av) break; if (parse_header(p, p->rbuf->buf + rpos, &msglen, &msgtype) == -1) - return (0); + return; if (rpos + msglen > av) break; p->rbuf->rptr = p->rbuf->buf + rpos; @@ -1847,11 +1848,11 @@ session_process_msg(struct peer *p) bgp_fsm(p, EVNT_CON_FATAL); } rpos += msglen; - if (++processed > MSG_PROCESS_LIMIT) + if (++processed > MSG_PROCESS_LIMIT) { + p->rpending = 1; break; + } } - if (p->rbuf == NULL) - return (1); if (rpos < av) { left = av - rpos; @@ -1859,8 +1860,6 @@ session_process_msg(struct peer *p) p->rbuf->wpos = left; } else p->rbuf->wpos = 0; - - return (1); } int Index: session.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/session.h,v retrieving revision 1.135 diff -u -p -r1.135 session.h --- session.h 31 Mar 2019 16:57:38 -0000 1.135 +++ session.h 2 Apr 2019 10:13:28 -0000 @@ -231,6 +231,7 @@ struct peer { u_int8_t demoted; u_int8_t passive; u_int8_t throttled; + u_int8_t rpending; }; extern time_t pauseaccept;