Line data Source code
1 : /* BGP I/O.
2 : * Implements packet I/O in a pthread.
3 : * Copyright (C) 2017 Cumulus Networks
4 : * Quentin Young
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 2 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; see the file COPYING; if not, write to the
18 : * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19 : * MA 02110-1301 USA
20 : */
21 :
22 : /* clang-format off */
23 : #include <zebra.h>
24 : #include <pthread.h> // for pthread_mutex_unlock, pthread_mutex_lock
25 : #include <sys/uio.h> // for writev
26 :
27 : #include "frr_pthread.h"
28 : #include "linklist.h" // for list_delete, list_delete_all_node, lis...
29 : #include "log.h" // for zlog_debug, safe_strerror, zlog_err
30 : #include "memory.h" // for MTYPE_TMP, XCALLOC, XFREE
31 : #include "network.h" // for ERRNO_IO_RETRY
32 : #include "stream.h" // for stream_get_endp, stream_getw_from, str...
33 : #include "ringbuf.h" // for ringbuf_remain, ringbuf_peek, ringbuf_...
34 : #include "thread.h" // for THREAD_OFF, THREAD_ARG, thread...
35 :
36 : #include "bgpd/bgp_io.h"
37 : #include "bgpd/bgp_debug.h" // for bgp_debug_neighbor_events, bgp_type_str
38 : #include "bgpd/bgp_errors.h" // for expanded error reference information
39 : #include "bgpd/bgp_fsm.h" // for BGP_EVENT_ADD, bgp_event
40 : #include "bgpd/bgp_packet.h" // for bgp_notify_io_invalid...
41 : #include "bgpd/bgp_trace.h" // for frrtraces
42 : #include "bgpd/bgpd.h" // for peer, BGP_MARKER_SIZE, bgp_master, bm
43 : /* clang-format on */
44 :
45 : /* forward declarations */
46 : static uint16_t bgp_write(struct peer *);
47 : static uint16_t bgp_read(struct peer *peer, int *code_p);
48 : static void bgp_process_writes(struct thread *);
49 : static void bgp_process_reads(struct thread *);
50 : static bool validate_header(struct peer *);
51 :
52 : /* generic i/o status codes */
53 : #define BGP_IO_TRANS_ERR (1 << 0) /* EAGAIN or similar occurred */
54 : #define BGP_IO_FATAL_ERR (1 << 1) /* some kind of fatal TCP error */
55 : #define BGP_IO_WORK_FULL_ERR (1 << 2) /* No room in work buffer */
56 :
57 : /* Thread external API ----------------------------------------------------- */
58 :
59 170 : void bgp_writes_on(struct peer *peer)
60 : {
61 170 : struct frr_pthread *fpt = bgp_pth_io;
62 170 : assert(fpt->running);
63 :
64 170 : assert(peer->status != Deleted);
65 170 : assert(peer->obuf);
66 170 : assert(peer->ibuf);
67 170 : assert(peer->ibuf_work);
68 170 : assert(!peer->t_connect_check_r);
69 170 : assert(!peer->t_connect_check_w);
70 170 : assert(peer->fd);
71 :
72 170 : thread_add_write(fpt->master, bgp_process_writes, peer, peer->fd,
73 : &peer->t_write);
74 170 : SET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON);
75 170 : }
76 :
77 351 : void bgp_writes_off(struct peer *peer)
78 : {
79 351 : struct frr_pthread *fpt = bgp_pth_io;
80 351 : assert(fpt->running);
81 :
82 351 : thread_cancel_async(fpt->master, &peer->t_write, NULL);
83 351 : THREAD_OFF(peer->t_generate_updgrp_packets);
84 :
85 351 : UNSET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON);
86 351 : }
87 :
88 59 : void bgp_reads_on(struct peer *peer)
89 : {
90 59 : struct frr_pthread *fpt = bgp_pth_io;
91 59 : assert(fpt->running);
92 :
93 59 : assert(peer->status != Deleted);
94 59 : assert(peer->ibuf);
95 59 : assert(peer->fd);
96 59 : assert(peer->ibuf_work);
97 59 : assert(peer->obuf);
98 59 : assert(!peer->t_connect_check_r);
99 59 : assert(!peer->t_connect_check_w);
100 59 : assert(peer->fd);
101 :
102 59 : thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
103 : &peer->t_read);
104 :
105 59 : SET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON);
106 59 : }
107 :
108 351 : void bgp_reads_off(struct peer *peer)
109 : {
110 351 : struct frr_pthread *fpt = bgp_pth_io;
111 351 : assert(fpt->running);
112 :
113 351 : thread_cancel_async(fpt->master, &peer->t_read, NULL);
114 351 : THREAD_OFF(peer->t_process_packet);
115 351 : THREAD_OFF(peer->t_process_packet_error);
116 :
117 351 : UNSET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON);
118 351 : }
119 :
120 : /* Thread internal functions ----------------------------------------------- */
121 :
122 : /*
123 : * Called from I/O pthread when a file descriptor has become ready for writing.
124 : */
125 165 : static void bgp_process_writes(struct thread *thread)
126 : {
127 165 : static struct peer *peer;
128 165 : peer = THREAD_ARG(thread);
129 165 : uint16_t status;
130 165 : bool reschedule;
131 165 : bool fatal = false;
132 :
133 165 : if (peer->fd < 0)
134 : return;
135 :
136 165 : struct frr_pthread *fpt = bgp_pth_io;
137 :
138 330 : frr_with_mutex (&peer->io_mtx) {
139 165 : status = bgp_write(peer);
140 165 : reschedule = (stream_fifo_head(peer->obuf) != NULL);
141 : }
142 :
143 : /* no problem */
144 165 : if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) {
145 165 : }
146 :
147 : /* problem */
148 165 : if (CHECK_FLAG(status, BGP_IO_FATAL_ERR)) {
149 : reschedule = false;
150 : fatal = true;
151 : }
152 :
153 : /* If suppress fib pending is enabled, route is advertised to peers when
154 : * the status is received from the FIB. The delay is added
155 : * to update group packet generate which will allow more routes to be
156 : * sent in the update message
157 : */
158 165 : if (reschedule) {
159 0 : thread_add_write(fpt->master, bgp_process_writes, peer,
160 : peer->fd, &peer->t_write);
161 165 : } else if (!fatal) {
162 165 : BGP_UPDATE_GROUP_TIMER_ON(&peer->t_generate_updgrp_packets,
163 : bgp_generate_updgrp_packets);
164 : }
165 : }
166 :
167 379 : static int read_ibuf_work(struct peer *peer)
168 : {
169 : /* static buffer for transferring packets */
170 : /* shorter alias to peer's input buffer */
171 379 : struct ringbuf *ibw = peer->ibuf_work;
172 : /* packet size as given by header */
173 379 : uint16_t pktsize = 0;
174 379 : struct stream *pkt;
175 :
176 : /* ============================================== */
177 758 : frr_with_mutex (&peer->io_mtx) {
178 379 : if (peer->ibuf->count >= bm->inq_limit)
179 0 : return -ENOMEM;
180 : }
181 :
182 : /* check that we have enough data for a header */
183 379 : if (ringbuf_remain(ibw) < BGP_HEADER_SIZE)
184 : return 0;
185 :
186 : /* check that header is valid */
187 218 : if (!validate_header(peer))
188 : return -EBADMSG;
189 :
190 : /* header is valid; retrieve packet size */
191 218 : ringbuf_peek(ibw, BGP_MARKER_SIZE, &pktsize, sizeof(pktsize));
192 :
193 218 : pktsize = ntohs(pktsize);
194 :
195 : /* if this fails we are seriously screwed */
196 218 : assert(pktsize <= peer->max_packet_size);
197 :
198 : /*
199 : * If we have that much data, chuck it into its own
200 : * stream and append to input queue for processing.
201 : *
202 : * Otherwise, come back later.
203 : */
204 218 : if (ringbuf_remain(ibw) < pktsize)
205 : return 0;
206 :
207 218 : pkt = stream_new(pktsize);
208 218 : assert(STREAM_WRITEABLE(pkt) == pktsize);
209 218 : assert(ringbuf_get(ibw, pkt->data, pktsize) == pktsize);
210 218 : stream_set_endp(pkt, pktsize);
211 :
212 218 : frrtrace(2, frr_bgp, packet_read, peer, pkt);
213 436 : frr_with_mutex (&peer->io_mtx) {
214 218 : stream_fifo_push(peer->ibuf, pkt);
215 : }
216 :
217 218 : return pktsize;
218 : }
219 :
220 : /*
221 : * Called from I/O pthread when a file descriptor has become ready for reading,
222 : * or has hung up.
223 : *
224 : * We read as much data as possible, process as many packets as we can and
225 : * place them on peer->ibuf for secondary processing by the main thread.
226 : */
227 175 : static void bgp_process_reads(struct thread *thread)
228 : {
229 : /* clang-format off */
230 175 : static struct peer *peer; /* peer to read from */
231 175 : uint16_t status; /* bgp_read status code */
232 175 : bool fatal = false; /* whether fatal error occurred */
233 175 : bool added_pkt = false; /* whether we pushed onto ->ibuf */
234 175 : int code = 0; /* FSM code if error occurred */
235 175 : bool ibuf_full = false; /* Is peer fifo IN Buffer full */
236 175 : static bool ibuf_full_logged; /* Have we logged full already */
237 175 : int ret = 1;
238 : /* clang-format on */
239 :
240 175 : peer = THREAD_ARG(thread);
241 :
242 175 : if (peer->fd < 0 || bm->terminating)
243 14 : return;
244 :
245 175 : struct frr_pthread *fpt = bgp_pth_io;
246 :
247 175 : frr_with_mutex (&peer->io_mtx) {
248 175 : status = bgp_read(peer, &code);
249 : }
250 :
251 : /* error checking phase */
252 175 : if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) {
253 : /* no problem; just don't process packets */
254 0 : goto done;
255 : }
256 :
257 175 : if (CHECK_FLAG(status, BGP_IO_FATAL_ERR)) {
258 : /* problem; tear down session */
259 14 : fatal = true;
260 :
261 : /* Handle the error in the main pthread, include the
262 : * specific state change from 'bgp_read'.
263 : */
264 14 : thread_add_event(bm->master, bgp_packet_process_error,
265 : peer, code, &peer->t_process_packet_error);
266 14 : goto done;
267 : }
268 :
269 379 : while (true) {
270 379 : ret = read_ibuf_work(peer);
271 379 : if (ret <= 0)
272 : break;
273 :
274 : added_pkt = true;
275 : }
276 :
277 161 : switch (ret) {
278 : case -EBADMSG:
279 : fatal = true;
280 : break;
281 0 : case -ENOMEM:
282 0 : ibuf_full = true;
283 0 : if (!ibuf_full_logged) {
284 0 : if (bgp_debug_neighbor_events(peer))
285 0 : zlog_debug(
286 : "%s [Event] Peer Input-Queue is full: limit (%u)",
287 : peer->host, bm->inq_limit);
288 :
289 0 : ibuf_full_logged = true;
290 : }
291 : break;
292 161 : default:
293 161 : ibuf_full_logged = false;
294 161 : break;
295 : }
296 :
297 175 : done:
298 : /* handle invalid header */
299 175 : if (fatal) {
300 : /* wipe buffer just in case someone screwed up */
301 14 : ringbuf_wipe(peer->ibuf_work);
302 14 : return;
303 : }
304 :
305 : /* ringbuf should be fully drained unless ibuf is full */
306 161 : if (!ibuf_full)
307 161 : assert(ringbuf_space(peer->ibuf_work) >= peer->max_packet_size);
308 :
309 161 : thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
310 : &peer->t_read);
311 161 : if (added_pkt)
312 161 : thread_add_event(bm->master, bgp_process_packet, peer, 0,
313 : &peer->t_process_packet);
314 : }
315 :
316 : /*
317 : * Flush peer output buffer.
318 : *
319 : * This function pops packets off of peer->obuf and writes them to peer->fd.
320 : * The amount of packets written is equal to the minimum of peer->wpkt_quanta
321 : * and the number of packets on the output buffer, unless an error occurs.
322 : *
323 : * If write() returns an error, the appropriate FSM event is generated.
324 : *
325 : * The return value is equal to the number of packets written
326 : * (which may be zero).
327 : */
328 165 : static uint16_t bgp_write(struct peer *peer)
329 165 : {
330 165 : uint8_t type;
331 165 : struct stream *s;
332 165 : int update_last_write = 0;
333 165 : unsigned int count;
334 165 : uint32_t uo = 0;
335 165 : uint16_t status = 0;
336 165 : uint32_t wpkt_quanta_old;
337 :
338 165 : int writenum = 0;
339 165 : int num;
340 165 : unsigned int iovsz;
341 165 : unsigned int strmsz;
342 165 : unsigned int total_written;
343 165 : time_t now;
344 :
345 165 : wpkt_quanta_old = atomic_load_explicit(&peer->bgp->wpkt_quanta,
346 : memory_order_relaxed);
347 165 : struct stream *ostreams[wpkt_quanta_old];
348 165 : struct stream **streams = ostreams;
349 165 : struct iovec iov[wpkt_quanta_old];
350 :
351 165 : s = stream_fifo_head(peer->obuf);
352 :
353 165 : if (!s)
354 17 : goto done;
355 :
356 : count = iovsz = 0;
357 352 : while (count < wpkt_quanta_old && iovsz < array_size(iov) && s) {
358 204 : ostreams[iovsz] = s;
359 204 : iov[iovsz].iov_base = stream_pnt(s);
360 204 : iov[iovsz].iov_len = STREAM_READABLE(s);
361 204 : writenum += STREAM_READABLE(s);
362 204 : s = s->next;
363 204 : ++iovsz;
364 204 : ++count;
365 : }
366 :
367 : strmsz = iovsz;
368 : total_written = 0;
369 :
370 148 : do {
371 148 : num = writev(peer->fd, iov, iovsz);
372 :
373 148 : if (num < 0) {
374 0 : if (!ERRNO_IO_RETRY(errno)) {
375 0 : BGP_EVENT_ADD(peer, TCP_fatal_error);
376 : SET_FLAG(status, BGP_IO_FATAL_ERR);
377 : } else {
378 : SET_FLAG(status, BGP_IO_TRANS_ERR);
379 : }
380 :
381 : break;
382 148 : } else if (num != writenum) {
383 : unsigned int msg_written = 0;
384 : unsigned int ic = iovsz;
385 :
386 0 : for (unsigned int i = 0; i < ic; i++) {
387 0 : size_t ss = iov[i].iov_len;
388 :
389 0 : if (ss > (unsigned int) num)
390 : break;
391 :
392 0 : msg_written++;
393 0 : iovsz--;
394 0 : writenum -= ss;
395 0 : num -= ss;
396 : }
397 :
398 0 : total_written += msg_written;
399 :
400 0 : assert(total_written < count);
401 :
402 0 : memmove(&iov, &iov[msg_written],
403 : sizeof(iov[0]) * iovsz);
404 0 : streams = &streams[msg_written];
405 0 : stream_forward_getp(streams[0], num);
406 0 : iov[0].iov_base = stream_pnt(streams[0]);
407 0 : iov[0].iov_len = STREAM_READABLE(streams[0]);
408 :
409 0 : writenum -= num;
410 0 : num = 0;
411 0 : assert(writenum > 0);
412 : } else {
413 : total_written = strmsz;
414 : }
415 :
416 148 : } while (num != writenum);
417 :
418 : /* Handle statistics */
419 352 : for (unsigned int i = 0; i < total_written; i++) {
420 204 : s = stream_fifo_pop(peer->obuf);
421 :
422 204 : assert(s == ostreams[i]);
423 :
424 : /* Retrieve BGP packet type. */
425 204 : stream_set_getp(s, BGP_MARKER_SIZE + 2);
426 204 : type = stream_getc(s);
427 :
428 204 : switch (type) {
429 42 : case BGP_MSG_OPEN:
430 42 : atomic_fetch_add_explicit(&peer->open_out, 1,
431 : memory_order_relaxed);
432 42 : break;
433 103 : case BGP_MSG_UPDATE:
434 103 : atomic_fetch_add_explicit(&peer->update_out, 1,
435 : memory_order_relaxed);
436 103 : uo++;
437 103 : break;
438 0 : case BGP_MSG_NOTIFY:
439 0 : atomic_fetch_add_explicit(&peer->notify_out, 1,
440 : memory_order_relaxed);
441 : /* Double start timer. */
442 0 : peer->v_start *= 2;
443 :
444 : /* Overflow check. */
445 0 : if (peer->v_start >= (60 * 2))
446 0 : peer->v_start = (60 * 2);
447 :
448 : /*
449 : * Handle Graceful Restart case where the state changes
450 : * to Connect instead of Idle.
451 : */
452 0 : BGP_EVENT_ADD(peer, BGP_Stop);
453 0 : goto done;
454 :
455 47 : case BGP_MSG_KEEPALIVE:
456 47 : atomic_fetch_add_explicit(&peer->keepalive_out, 1,
457 : memory_order_relaxed);
458 47 : break;
459 12 : case BGP_MSG_ROUTE_REFRESH_NEW:
460 : case BGP_MSG_ROUTE_REFRESH_OLD:
461 12 : atomic_fetch_add_explicit(&peer->refresh_out, 1,
462 : memory_order_relaxed);
463 12 : break;
464 0 : case BGP_MSG_CAPABILITY:
465 0 : atomic_fetch_add_explicit(&peer->dynamic_cap_out, 1,
466 : memory_order_relaxed);
467 0 : break;
468 : }
469 :
470 204 : stream_free(s);
471 204 : ostreams[i] = NULL;
472 204 : update_last_write = 1;
473 : }
474 :
475 148 : done : {
476 165 : now = monotime(NULL);
477 : /*
478 : * Update last_update if UPDATEs were written.
479 : * Note: that these are only updated at end,
480 : * not per message (i.e., per loop)
481 : */
482 165 : if (uo)
483 51 : atomic_store_explicit(&peer->last_update, now,
484 : memory_order_relaxed);
485 :
486 : /* If we TXed any flavor of packet */
487 165 : if (update_last_write) {
488 148 : atomic_store_explicit(&peer->last_write, now,
489 : memory_order_relaxed);
490 148 : peer->last_sendq_ok = now;
491 : }
492 : }
493 :
494 165 : return status;
495 : }
496 :
497 : /*
498 : * Reads a chunk of data from peer->fd into peer->ibuf_work.
499 : *
500 : * code_p
501 : * Pointer to location to store FSM event code in case of fatal error.
502 : *
503 : * @return status flag (see top-of-file)
504 : */
505 175 : static uint16_t bgp_read(struct peer *peer, int *code_p)
506 : {
507 175 : size_t readsize; /* how many bytes we want to read */
508 175 : ssize_t nbytes; /* how many bytes we actually read */
509 175 : size_t ibuf_work_space; /* space we can read into the work buf */
510 175 : uint16_t status = 0;
511 :
512 175 : ibuf_work_space = ringbuf_space(peer->ibuf_work);
513 :
514 175 : if (ibuf_work_space == 0) {
515 175 : SET_FLAG(status, BGP_IO_WORK_FULL_ERR);
516 : return status;
517 : }
518 :
519 175 : readsize = MIN(ibuf_work_space, sizeof(peer->ibuf_scratch));
520 :
521 175 : nbytes = read(peer->fd, peer->ibuf_scratch, readsize);
522 :
523 : /* EAGAIN or EWOULDBLOCK; come back later */
524 175 : if (nbytes < 0 && ERRNO_IO_RETRY(errno)) {
525 : SET_FLAG(status, BGP_IO_TRANS_ERR);
526 0 : } else if (nbytes < 0) {
527 : /* Fatal error; tear down session */
528 0 : flog_err(EC_BGP_UPDATE_RCV,
529 : "%s [Error] bgp_read_packet error: %s", peer->host,
530 : safe_strerror(errno));
531 :
532 : /* Handle the error in the main pthread. */
533 0 : if (code_p)
534 0 : *code_p = TCP_fatal_error;
535 :
536 : SET_FLAG(status, BGP_IO_FATAL_ERR);
537 :
538 175 : } else if (nbytes == 0) {
539 : /* Received EOF / TCP session closed */
540 14 : if (bgp_debug_neighbor_events(peer))
541 0 : zlog_debug("%s [Event] BGP connection closed fd %d",
542 : peer->host, peer->fd);
543 :
544 : /* Handle the error in the main pthread. */
545 14 : if (code_p)
546 14 : *code_p = TCP_connection_closed;
547 :
548 : SET_FLAG(status, BGP_IO_FATAL_ERR);
549 : } else {
550 161 : assert(ringbuf_put(peer->ibuf_work, peer->ibuf_scratch, nbytes)
551 : == (size_t)nbytes);
552 : }
553 :
554 : return status;
555 : }
556 :
557 : /*
558 : * Called after we have read a BGP packet header. Validates marker, message
559 : * type and packet length. If any of these aren't correct, sends a notify.
560 : *
561 : * Assumes that there are at least BGP_HEADER_SIZE readable bytes in the input
562 : * buffer.
563 : */
564 218 : static bool validate_header(struct peer *peer)
565 : {
566 218 : uint16_t size;
567 218 : uint8_t type;
568 218 : struct ringbuf *pkt = peer->ibuf_work;
569 :
570 218 : static const uint8_t m_correct[BGP_MARKER_SIZE] = {
571 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
572 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
573 218 : uint8_t m_rx[BGP_MARKER_SIZE] = {0x00};
574 :
575 218 : if (ringbuf_peek(pkt, 0, m_rx, BGP_MARKER_SIZE) != BGP_MARKER_SIZE)
576 : return false;
577 :
578 218 : if (memcmp(m_correct, m_rx, BGP_MARKER_SIZE) != 0) {
579 0 : bgp_notify_io_invalid(peer, BGP_NOTIFY_HEADER_ERR,
580 : BGP_NOTIFY_HEADER_NOT_SYNC, NULL, 0);
581 0 : return false;
582 : }
583 :
584 : /* Get size and type in network byte order. */
585 218 : ringbuf_peek(pkt, BGP_MARKER_SIZE, &size, sizeof(size));
586 218 : ringbuf_peek(pkt, BGP_MARKER_SIZE + 2, &type, sizeof(type));
587 :
588 218 : size = ntohs(size);
589 :
590 : /* BGP type check. */
591 218 : if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE
592 : && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE
593 : && type != BGP_MSG_ROUTE_REFRESH_NEW
594 218 : && type != BGP_MSG_ROUTE_REFRESH_OLD
595 0 : && type != BGP_MSG_CAPABILITY) {
596 0 : if (bgp_debug_neighbor_events(peer))
597 0 : zlog_debug("%s unknown message type 0x%02x", peer->host,
598 : type);
599 :
600 0 : bgp_notify_io_invalid(peer, BGP_NOTIFY_HEADER_ERR,
601 : BGP_NOTIFY_HEADER_BAD_MESTYPE, &type, 1);
602 0 : return false;
603 : }
604 :
605 : /* Minimum packet length check. */
606 218 : if ((size < BGP_HEADER_SIZE) || (size > peer->max_packet_size)
607 218 : || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE)
608 218 : || (type == BGP_MSG_UPDATE && size < BGP_MSG_UPDATE_MIN_SIZE)
609 218 : || (type == BGP_MSG_NOTIFY && size < BGP_MSG_NOTIFY_MIN_SIZE)
610 218 : || (type == BGP_MSG_KEEPALIVE && size != BGP_MSG_KEEPALIVE_MIN_SIZE)
611 218 : || (type == BGP_MSG_ROUTE_REFRESH_NEW
612 12 : && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE)
613 218 : || (type == BGP_MSG_ROUTE_REFRESH_OLD
614 0 : && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE)
615 218 : || (type == BGP_MSG_CAPABILITY
616 0 : && size < BGP_MSG_CAPABILITY_MIN_SIZE)) {
617 0 : if (bgp_debug_neighbor_events(peer)) {
618 0 : zlog_debug("%s bad message length - %d for %s",
619 : peer->host, size,
620 : type == 128 ? "ROUTE-REFRESH"
621 : : bgp_type_str[(int)type]);
622 : }
623 :
624 0 : uint16_t nsize = htons(size);
625 :
626 0 : bgp_notify_io_invalid(peer, BGP_NOTIFY_HEADER_ERR,
627 : BGP_NOTIFY_HEADER_BAD_MESLEN,
628 : (unsigned char *)&nsize, 2);
629 0 : return false;
630 : }
631 :
632 : return true;
633 : }
|