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 240 : void bgp_writes_on(struct peer *peer)
60 : {
61 240 : struct frr_pthread *fpt = bgp_pth_io;
62 240 : assert(fpt->running);
63 :
64 240 : assert(peer->status != Deleted);
65 240 : assert(peer->obuf);
66 240 : assert(peer->ibuf);
67 240 : assert(peer->ibuf_work);
68 240 : assert(!peer->t_connect_check_r);
69 240 : assert(!peer->t_connect_check_w);
70 240 : assert(peer->fd);
71 :
72 240 : thread_add_write(fpt->master, bgp_process_writes, peer, peer->fd,
73 : &peer->t_write);
74 240 : SET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON);
75 240 : }
76 :
77 531 : void bgp_writes_off(struct peer *peer)
78 : {
79 531 : struct frr_pthread *fpt = bgp_pth_io;
80 531 : assert(fpt->running);
81 :
82 531 : thread_cancel_async(fpt->master, &peer->t_write, NULL);
83 531 : THREAD_OFF(peer->t_generate_updgrp_packets);
84 :
85 531 : UNSET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON);
86 531 : }
87 :
88 92 : void bgp_reads_on(struct peer *peer)
89 : {
90 92 : struct frr_pthread *fpt = bgp_pth_io;
91 92 : assert(fpt->running);
92 :
93 92 : assert(peer->status != Deleted);
94 92 : assert(peer->ibuf);
95 92 : assert(peer->fd);
96 92 : assert(peer->ibuf_work);
97 92 : assert(peer->obuf);
98 92 : assert(!peer->t_connect_check_r);
99 92 : assert(!peer->t_connect_check_w);
100 92 : assert(peer->fd);
101 :
102 92 : thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
103 : &peer->t_read);
104 :
105 92 : SET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON);
106 92 : }
107 :
108 531 : void bgp_reads_off(struct peer *peer)
109 : {
110 531 : struct frr_pthread *fpt = bgp_pth_io;
111 531 : assert(fpt->running);
112 :
113 531 : thread_cancel_async(fpt->master, &peer->t_read, NULL);
114 531 : THREAD_OFF(peer->t_process_packet);
115 531 : THREAD_OFF(peer->t_process_packet_error);
116 :
117 531 : UNSET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON);
118 531 : }
119 :
120 : /* Thread internal functions ----------------------------------------------- */
121 :
122 : /*
123 : * Called from I/O pthread when a file descriptor has become ready for writing.
124 : */
125 236 : static void bgp_process_writes(struct thread *thread)
126 : {
127 236 : static struct peer *peer;
128 236 : peer = THREAD_ARG(thread);
129 236 : uint16_t status;
130 236 : bool reschedule;
131 236 : bool fatal = false;
132 :
133 236 : if (peer->fd < 0)
134 : return;
135 :
136 236 : struct frr_pthread *fpt = bgp_pth_io;
137 :
138 472 : frr_with_mutex (&peer->io_mtx) {
139 236 : status = bgp_write(peer);
140 236 : reschedule = (stream_fifo_head(peer->obuf) != NULL);
141 : }
142 :
143 : /* no problem */
144 236 : if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) {
145 236 : }
146 :
147 : /* problem */
148 236 : 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 236 : if (reschedule) {
159 0 : thread_add_write(fpt->master, bgp_process_writes, peer,
160 : peer->fd, &peer->t_write);
161 236 : } else if (!fatal) {
162 236 : BGP_UPDATE_GROUP_TIMER_ON(&peer->t_generate_updgrp_packets,
163 : bgp_generate_updgrp_packets);
164 : }
165 : }
166 :
167 532 : static int read_ibuf_work(struct peer *peer)
168 : {
169 : /* static buffer for transferring packets */
170 : /* shorter alias to peer's input buffer */
171 532 : struct ringbuf *ibw = peer->ibuf_work;
172 : /* packet size as given by header */
173 532 : uint16_t pktsize = 0;
174 532 : struct stream *pkt;
175 :
176 : /* ============================================== */
177 1064 : frr_with_mutex (&peer->io_mtx) {
178 532 : if (peer->ibuf->count >= bm->inq_limit)
179 0 : return -ENOMEM;
180 : }
181 :
182 : /* check that we have enough data for a header */
183 532 : if (ringbuf_remain(ibw) < BGP_HEADER_SIZE)
184 : return 0;
185 :
186 : /* check that header is valid */
187 300 : if (!validate_header(peer))
188 : return -EBADMSG;
189 :
190 : /* header is valid; retrieve packet size */
191 300 : ringbuf_peek(ibw, BGP_MARKER_SIZE, &pktsize, sizeof(pktsize));
192 :
193 300 : pktsize = ntohs(pktsize);
194 :
195 : /* if this fails we are seriously screwed */
196 300 : 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 300 : if (ringbuf_remain(ibw) < pktsize)
205 : return 0;
206 :
207 300 : pkt = stream_new(pktsize);
208 300 : assert(STREAM_WRITEABLE(pkt) == pktsize);
209 300 : assert(ringbuf_get(ibw, pkt->data, pktsize) == pktsize);
210 300 : stream_set_endp(pkt, pktsize);
211 :
212 300 : frrtrace(2, frr_bgp, packet_read, peer, pkt);
213 600 : frr_with_mutex (&peer->io_mtx) {
214 300 : stream_fifo_push(peer->ibuf, pkt);
215 : }
216 :
217 300 : 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 256 : static void bgp_process_reads(struct thread *thread)
228 : {
229 : /* clang-format off */
230 256 : static struct peer *peer; /* peer to read from */
231 256 : uint16_t status; /* bgp_read status code */
232 256 : bool fatal = false; /* whether fatal error occurred */
233 256 : bool added_pkt = false; /* whether we pushed onto ->ibuf */
234 256 : int code = 0; /* FSM code if error occurred */
235 256 : bool ibuf_full = false; /* Is peer fifo IN Buffer full */
236 256 : static bool ibuf_full_logged; /* Have we logged full already */
237 256 : int ret = 1;
238 : /* clang-format on */
239 :
240 256 : peer = THREAD_ARG(thread);
241 :
242 256 : if (peer->fd < 0 || bm->terminating)
243 24 : return;
244 :
245 255 : struct frr_pthread *fpt = bgp_pth_io;
246 :
247 255 : frr_with_mutex (&peer->io_mtx) {
248 255 : status = bgp_read(peer, &code);
249 : }
250 :
251 : /* error checking phase */
252 255 : if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) {
253 : /* no problem; just don't process packets */
254 0 : goto done;
255 : }
256 :
257 255 : if (CHECK_FLAG(status, BGP_IO_FATAL_ERR)) {
258 : /* problem; tear down session */
259 23 : fatal = true;
260 :
261 : /* Handle the error in the main pthread, include the
262 : * specific state change from 'bgp_read'.
263 : */
264 23 : thread_add_event(bm->master, bgp_packet_process_error,
265 : peer, code, &peer->t_process_packet_error);
266 23 : goto done;
267 : }
268 :
269 532 : while (true) {
270 532 : ret = read_ibuf_work(peer);
271 532 : if (ret <= 0)
272 : break;
273 :
274 : added_pkt = true;
275 : }
276 :
277 232 : 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 232 : default:
293 232 : ibuf_full_logged = false;
294 232 : break;
295 : }
296 :
297 255 : done:
298 : /* handle invalid header */
299 255 : if (fatal) {
300 : /* wipe buffer just in case someone screwed up */
301 23 : ringbuf_wipe(peer->ibuf_work);
302 23 : return;
303 : }
304 :
305 : /* ringbuf should be fully drained unless ibuf is full */
306 232 : if (!ibuf_full)
307 232 : assert(ringbuf_space(peer->ibuf_work) >= peer->max_packet_size);
308 :
309 232 : thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
310 : &peer->t_read);
311 232 : if (added_pkt)
312 232 : 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 236 : static uint16_t bgp_write(struct peer *peer)
329 236 : {
330 236 : uint8_t type;
331 236 : struct stream *s;
332 236 : int update_last_write = 0;
333 236 : unsigned int count;
334 236 : uint32_t uo = 0;
335 236 : uint16_t status = 0;
336 236 : uint32_t wpkt_quanta_old;
337 :
338 236 : int writenum = 0;
339 236 : int num;
340 236 : unsigned int iovsz;
341 236 : unsigned int strmsz;
342 236 : unsigned int total_written;
343 236 : time_t now;
344 :
345 236 : wpkt_quanta_old = atomic_load_explicit(&peer->bgp->wpkt_quanta,
346 : memory_order_relaxed);
347 236 : struct stream *ostreams[wpkt_quanta_old];
348 236 : struct stream **streams = ostreams;
349 236 : struct iovec iov[wpkt_quanta_old];
350 :
351 236 : s = stream_fifo_head(peer->obuf);
352 :
353 236 : if (!s)
354 25 : goto done;
355 :
356 : count = iovsz = 0;
357 488 : while (count < wpkt_quanta_old && iovsz < array_size(iov) && s) {
358 277 : ostreams[iovsz] = s;
359 277 : iov[iovsz].iov_base = stream_pnt(s);
360 277 : iov[iovsz].iov_len = STREAM_READABLE(s);
361 277 : writenum += STREAM_READABLE(s);
362 277 : s = s->next;
363 277 : ++iovsz;
364 277 : ++count;
365 : }
366 :
367 : strmsz = iovsz;
368 : total_written = 0;
369 :
370 211 : do {
371 211 : num = writev(peer->fd, iov, iovsz);
372 :
373 211 : 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 211 : } 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 211 : } while (num != writenum);
417 :
418 : /* Handle statistics */
419 488 : for (unsigned int i = 0; i < total_written; i++) {
420 277 : s = stream_fifo_pop(peer->obuf);
421 :
422 277 : assert(s == ostreams[i]);
423 :
424 : /* Retrieve BGP packet type. */
425 277 : stream_set_getp(s, BGP_MARKER_SIZE + 2);
426 277 : type = stream_getc(s);
427 :
428 277 : switch (type) {
429 67 : case BGP_MSG_OPEN:
430 67 : atomic_fetch_add_explicit(&peer->open_out, 1,
431 : memory_order_relaxed);
432 67 : break;
433 134 : case BGP_MSG_UPDATE:
434 134 : atomic_fetch_add_explicit(&peer->update_out, 1,
435 : memory_order_relaxed);
436 134 : uo++;
437 134 : 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 64 : case BGP_MSG_KEEPALIVE:
456 64 : atomic_fetch_add_explicit(&peer->keepalive_out, 1,
457 : memory_order_relaxed);
458 64 : 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 277 : stream_free(s);
471 277 : ostreams[i] = NULL;
472 277 : update_last_write = 1;
473 : }
474 :
475 211 : done : {
476 236 : 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 236 : if (uo)
483 72 : atomic_store_explicit(&peer->last_update, now,
484 : memory_order_relaxed);
485 :
486 : /* If we TXed any flavor of packet */
487 236 : if (update_last_write) {
488 211 : atomic_store_explicit(&peer->last_write, now,
489 : memory_order_relaxed);
490 211 : peer->last_sendq_ok = now;
491 : }
492 : }
493 :
494 236 : 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 255 : static uint16_t bgp_read(struct peer *peer, int *code_p)
506 : {
507 255 : size_t readsize; /* how many bytes we want to read */
508 255 : ssize_t nbytes; /* how many bytes we actually read */
509 255 : size_t ibuf_work_space; /* space we can read into the work buf */
510 255 : uint16_t status = 0;
511 :
512 255 : ibuf_work_space = ringbuf_space(peer->ibuf_work);
513 :
514 255 : if (ibuf_work_space == 0) {
515 255 : SET_FLAG(status, BGP_IO_WORK_FULL_ERR);
516 : return status;
517 : }
518 :
519 255 : readsize = MIN(ibuf_work_space, sizeof(peer->ibuf_scratch));
520 :
521 255 : nbytes = read(peer->fd, peer->ibuf_scratch, readsize);
522 :
523 : /* EAGAIN or EWOULDBLOCK; come back later */
524 255 : 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 255 : } else if (nbytes == 0) {
539 : /* Received EOF / TCP session closed */
540 23 : 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 23 : if (code_p)
546 23 : *code_p = TCP_connection_closed;
547 :
548 : SET_FLAG(status, BGP_IO_FATAL_ERR);
549 : } else {
550 232 : 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 300 : static bool validate_header(struct peer *peer)
565 : {
566 300 : uint16_t size;
567 300 : uint8_t type;
568 300 : struct ringbuf *pkt = peer->ibuf_work;
569 :
570 300 : 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 300 : uint8_t m_rx[BGP_MARKER_SIZE] = {0x00};
574 :
575 300 : if (ringbuf_peek(pkt, 0, m_rx, BGP_MARKER_SIZE) != BGP_MARKER_SIZE)
576 : return false;
577 :
578 300 : 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 300 : ringbuf_peek(pkt, BGP_MARKER_SIZE, &size, sizeof(size));
586 300 : ringbuf_peek(pkt, BGP_MARKER_SIZE + 2, &type, sizeof(type));
587 :
588 300 : size = ntohs(size);
589 :
590 : /* BGP type check. */
591 300 : 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 300 : && 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 300 : if ((size < BGP_HEADER_SIZE) || (size > peer->max_packet_size)
607 300 : || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE)
608 300 : || (type == BGP_MSG_UPDATE && size < BGP_MSG_UPDATE_MIN_SIZE)
609 300 : || (type == BGP_MSG_NOTIFY && size < BGP_MSG_NOTIFY_MIN_SIZE)
610 300 : || (type == BGP_MSG_KEEPALIVE && size != BGP_MSG_KEEPALIVE_MIN_SIZE)
611 300 : || (type == BGP_MSG_ROUTE_REFRESH_NEW
612 12 : && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE)
613 300 : || (type == BGP_MSG_ROUTE_REFRESH_OLD
614 0 : && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE)
615 300 : || (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 : }
|