]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_msdp_packet.c
a6f318e61e60b2f4371b23018ad17a7a5fa46c86
[mirror_frr.git] / pimd / pim_msdp_packet.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * IP MSDP packet helper
4 * Copyright (C) 2016 Cumulus Networks, Inc.
5 */
6 #include <zebra.h>
7
8 #include <lib/log.h>
9 #include <lib/network.h>
10 #include <lib/stream.h>
11 #include <lib/thread.h>
12 #include <lib/vty.h>
13 #include <lib/lib_errors.h>
14
15 #include "pimd.h"
16 #include "pim_instance.h"
17 #include "pim_str.h"
18 #include "pim_errors.h"
19
20 #include "pim_msdp.h"
21 #include "pim_msdp_packet.h"
22 #include "pim_msdp_socket.h"
23
24 static char *pim_msdp_pkt_type_dump(enum pim_msdp_tlv type, char *buf,
25 int buf_size)
26 {
27 switch (type) {
28 case PIM_MSDP_V4_SOURCE_ACTIVE:
29 snprintf(buf, buf_size, "%s", "SA");
30 break;
31 case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST:
32 snprintf(buf, buf_size, "%s", "SA_REQ");
33 break;
34 case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE:
35 snprintf(buf, buf_size, "%s", "SA_RESP");
36 break;
37 case PIM_MSDP_KEEPALIVE:
38 snprintf(buf, buf_size, "%s", "KA");
39 break;
40 case PIM_MSDP_RESERVED:
41 snprintf(buf, buf_size, "%s", "RSVD");
42 break;
43 case PIM_MSDP_TRACEROUTE_PROGRESS:
44 snprintf(buf, buf_size, "%s", "TRACE_PROG");
45 break;
46 case PIM_MSDP_TRACEROUTE_REPLY:
47 snprintf(buf, buf_size, "%s", "TRACE_REPLY");
48 break;
49 default:
50 snprintf(buf, buf_size, "UNK-%d", type);
51 }
52 return buf;
53 }
54
55 static void pim_msdp_pkt_sa_dump_one(struct stream *s)
56 {
57 pim_sgaddr sg;
58
59 /* just throw away the three reserved bytes */
60 stream_get3(s);
61 /* throw away the prefix length also */
62 stream_getc(s);
63
64 memset(&sg, 0, sizeof(sg));
65 sg.grp.s_addr = stream_get_ipv4(s);
66 sg.src.s_addr = stream_get_ipv4(s);
67
68 zlog_debug(" sg %pSG", &sg);
69 }
70
71 static void pim_msdp_pkt_sa_dump(struct stream *s)
72 {
73 const size_t header_length = PIM_MSDP_SA_X_SIZE - PIM_MSDP_HEADER_SIZE;
74 size_t payload_length;
75 int entry_cnt;
76 int i;
77 struct in_addr rp; /* Last RP address associated with this SA */
78
79 if (header_length > STREAM_READABLE(s)) {
80 zlog_err("BUG MSDP SA bad header (readable %zu expected %zu)",
81 STREAM_READABLE(s), header_length);
82 return;
83 }
84
85 entry_cnt = stream_getc(s);
86 rp.s_addr = stream_get_ipv4(s);
87
88 if (PIM_DEBUG_MSDP_PACKETS) {
89 char rp_str[INET_ADDRSTRLEN];
90 pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
91 zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
92 }
93
94 payload_length = (size_t)entry_cnt * PIM_MSDP_SA_ONE_ENTRY_SIZE;
95 if (payload_length > STREAM_READABLE(s)) {
96 zlog_err("BUG MSDP SA bad length (readable %zu expected %zu)",
97 STREAM_READABLE(s), payload_length);
98 return;
99 }
100
101 /* dump SAs */
102 for (i = 0; i < entry_cnt; ++i) {
103 pim_msdp_pkt_sa_dump_one(s);
104 }
105 }
106
107 static void pim_msdp_pkt_dump(struct pim_msdp_peer *mp, int type, int len,
108 bool rx, struct stream *s)
109 {
110 char type_str[PIM_MSDP_PKT_TYPE_STRLEN];
111
112 pim_msdp_pkt_type_dump(type, type_str, sizeof(type_str));
113
114 zlog_debug("MSDP peer %s pkt %s type %s len %d", mp->key_str,
115 rx ? "rx" : "tx", type_str, len);
116
117 if (!s) {
118 return;
119 }
120
121 if (len < PIM_MSDP_HEADER_SIZE) {
122 zlog_err("invalid MSDP header length");
123 return;
124 }
125
126 switch (type) {
127 case PIM_MSDP_V4_SOURCE_ACTIVE:
128 pim_msdp_pkt_sa_dump(s);
129 break;
130 default:;
131 }
132 }
133
134 /* Check file descriptor whether connect is established. */
135 static void pim_msdp_connect_check(struct pim_msdp_peer *mp)
136 {
137 int status;
138 socklen_t slen;
139 int ret;
140
141 if (mp->state != PIM_MSDP_CONNECTING) {
142 /* if we are here it means we are not in a connecting or
143 * established state
144 * for now treat this as a fatal error */
145 pim_msdp_peer_reset_tcp_conn(mp, "invalid-state");
146 return;
147 }
148
149 PIM_MSDP_PEER_READ_OFF(mp);
150 PIM_MSDP_PEER_WRITE_OFF(mp);
151
152 /* Check file descriptor. */
153 slen = sizeof(status);
154 ret = getsockopt(mp->fd, SOL_SOCKET, SO_ERROR, (void *)&status, &slen);
155
156 /* If getsockopt is fail, this is fatal error. */
157 if (ret < 0) {
158 flog_err_sys(EC_LIB_SOCKET,
159 "can't get sockopt for nonblocking connect");
160 pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
161 return;
162 }
163
164 /* When status is 0 then TCP connection is established. */
165 if (PIM_DEBUG_MSDP_INTERNAL) {
166 zlog_debug("MSDP peer %s pim_connect_check %s", mp->key_str,
167 status ? "fail" : "success");
168 }
169 if (status == 0) {
170 pim_msdp_peer_established(mp);
171 } else {
172 pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
173 }
174 }
175
176 static void pim_msdp_pkt_delete(struct pim_msdp_peer *mp)
177 {
178 stream_free(stream_fifo_pop(mp->obuf));
179 }
180
181 static void pim_msdp_pkt_add(struct pim_msdp_peer *mp, struct stream *s)
182 {
183 stream_fifo_push(mp->obuf, s);
184 }
185
186 static void pim_msdp_write_proceed_actions(struct pim_msdp_peer *mp)
187 {
188 if (stream_fifo_head(mp->obuf)) {
189 PIM_MSDP_PEER_WRITE_ON(mp);
190 }
191 }
192
193 void pim_msdp_write(struct thread *thread)
194 {
195 struct pim_msdp_peer *mp;
196 struct stream *s;
197 int num;
198 enum pim_msdp_tlv type;
199 int len;
200 int work_cnt = 0;
201 int work_max_cnt = 100;
202
203 mp = THREAD_ARG(thread);
204 mp->t_write = NULL;
205
206 if (PIM_DEBUG_MSDP_INTERNAL) {
207 zlog_debug("MSDP peer %s pim_msdp_write", mp->key_str);
208 }
209 if (mp->fd < 0) {
210 return;
211 }
212
213 /* check if TCP connection is established */
214 if (mp->state != PIM_MSDP_ESTABLISHED) {
215 pim_msdp_connect_check(mp);
216 return;
217 }
218
219 s = stream_fifo_head(mp->obuf);
220 if (!s) {
221 pim_msdp_write_proceed_actions(mp);
222 return;
223 }
224
225 /* Nonblocking write until TCP output buffer is full */
226 do {
227 int writenum;
228
229 /* Number of bytes to be sent */
230 writenum = stream_get_endp(s) - stream_get_getp(s);
231
232 /* Call write() system call */
233 num = write(mp->fd, stream_pnt(s), writenum);
234 if (num < 0) {
235 /* write failed either retry needed or error */
236 if (ERRNO_IO_RETRY(errno)) {
237 if (PIM_DEBUG_MSDP_INTERNAL) {
238 zlog_debug(
239 "MSDP peer %s pim_msdp_write io retry",
240 mp->key_str);
241 }
242 break;
243 }
244
245 pim_msdp_peer_reset_tcp_conn(mp, "pkt-tx-failed");
246 return;
247 }
248
249 if (num != writenum) {
250 /* Partial write */
251 stream_forward_getp(s, num);
252 if (PIM_DEBUG_MSDP_INTERNAL) {
253 zlog_debug(
254 "MSDP peer %s pim_msdp_partial_write",
255 mp->key_str);
256 }
257 break;
258 }
259
260 /* Retrieve msdp packet type. */
261 stream_set_getp(s, 0);
262 type = stream_getc(s);
263 len = stream_getw(s);
264 switch (type) {
265 case PIM_MSDP_KEEPALIVE:
266 mp->ka_tx_cnt++;
267 break;
268 case PIM_MSDP_V4_SOURCE_ACTIVE:
269 mp->sa_tx_cnt++;
270 break;
271 case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST:
272 case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE:
273 case PIM_MSDP_RESERVED:
274 case PIM_MSDP_TRACEROUTE_PROGRESS:
275 case PIM_MSDP_TRACEROUTE_REPLY:
276 break;
277 }
278 if (PIM_DEBUG_MSDP_PACKETS) {
279 pim_msdp_pkt_dump(mp, type, len, false /*rx*/, s);
280 }
281
282 /* packet sent delete it. */
283 pim_msdp_pkt_delete(mp);
284
285 ++work_cnt;
286 /* may need to pause if we have done too much work in this
287 * loop */
288 if (work_cnt >= work_max_cnt) {
289 break;
290 }
291 } while ((s = stream_fifo_head(mp->obuf)) != NULL);
292 pim_msdp_write_proceed_actions(mp);
293
294 if (PIM_DEBUG_MSDP_INTERNAL) {
295 zlog_debug("MSDP peer %s pim_msdp_write wrote %d packets",
296 mp->key_str, work_cnt);
297 }
298 }
299
300 static void pim_msdp_pkt_send(struct pim_msdp_peer *mp, struct stream *s)
301 {
302 /* Add packet to the end of list. */
303 pim_msdp_pkt_add(mp, s);
304
305 PIM_MSDP_PEER_WRITE_ON(mp);
306 }
307
308 void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp)
309 {
310 struct stream *s;
311
312 if (mp->state != PIM_MSDP_ESTABLISHED) {
313 /* don't tx anything unless a session is established */
314 return;
315 }
316 s = stream_new(PIM_MSDP_KA_TLV_MAX_SIZE);
317 stream_putc(s, PIM_MSDP_KEEPALIVE);
318 stream_putw(s, PIM_MSDP_KA_TLV_MAX_SIZE);
319
320 pim_msdp_pkt_send(mp, s);
321 }
322
323 static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim,
324 struct pim_msdp_peer *mp)
325 {
326 struct stream *s;
327
328 if (mp->state != PIM_MSDP_ESTABLISHED) {
329 /* don't tx anything unless a session is established */
330 return;
331 }
332 s = stream_dup(pim->msdp.work_obuf);
333 if (s) {
334 pim_msdp_pkt_send(mp, s);
335 mp->flags |= PIM_MSDP_PEERF_SA_JUST_SENT;
336 }
337 }
338
339 /* push the stream into the obuf fifo of all the peers */
340 static void pim_msdp_pkt_sa_push(struct pim_instance *pim,
341 struct pim_msdp_peer *mp)
342 {
343 struct listnode *mpnode;
344
345 if (mp) {
346 pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
347 } else {
348 for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
349 if (PIM_DEBUG_MSDP_INTERNAL) {
350 zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push",
351 mp->key_str);
352 }
353 pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
354 }
355 }
356 }
357
358 static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt,
359 struct in_addr rp)
360 {
361 int curr_tlv_ecnt;
362
363 stream_reset(pim->msdp.work_obuf);
364 curr_tlv_ecnt = local_cnt > PIM_MSDP_SA_MAX_ENTRY_CNT
365 ? PIM_MSDP_SA_MAX_ENTRY_CNT
366 : local_cnt;
367 local_cnt -= curr_tlv_ecnt;
368 stream_putc(pim->msdp.work_obuf, PIM_MSDP_V4_SOURCE_ACTIVE);
369 stream_putw(pim->msdp.work_obuf,
370 PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt));
371 stream_putc(pim->msdp.work_obuf, curr_tlv_ecnt);
372 stream_put_ipv4(pim->msdp.work_obuf, rp.s_addr);
373
374 return local_cnt;
375 }
376
377 static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa)
378 {
379 stream_put3(sa->pim->msdp.work_obuf, 0 /* reserved */);
380 stream_putc(sa->pim->msdp.work_obuf, 32 /* sprefix len */);
381 stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.grp.s_addr);
382 stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr);
383 }
384
385 static void pim_msdp_pkt_sa_gen(struct pim_instance *pim,
386 struct pim_msdp_peer *mp)
387 {
388 struct listnode *sanode;
389 struct pim_msdp_sa *sa;
390 int sa_count;
391 int local_cnt = pim->msdp.local_cnt;
392
393 sa_count = 0;
394 if (PIM_DEBUG_MSDP_INTERNAL) {
395 zlog_debug(" sa gen %d", local_cnt);
396 }
397
398 local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt,
399 pim->msdp.originator_id);
400
401 for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
402 if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
403 /* current implementation of MSDP is for anycast i.e.
404 * full mesh. so
405 * no re-forwarding of SAs that we learnt from other
406 * peers */
407 continue;
408 }
409 /* add sa into scratch pad */
410 pim_msdp_pkt_sa_fill_one(sa);
411 ++sa_count;
412 if (sa_count >= PIM_MSDP_SA_MAX_ENTRY_CNT) {
413 pim_msdp_pkt_sa_push(pim, mp);
414 /* reset headers */
415 sa_count = 0;
416 if (PIM_DEBUG_MSDP_INTERNAL) {
417 zlog_debug(" sa gen for remainder %d",
418 local_cnt);
419 }
420 local_cnt = pim_msdp_pkt_sa_fill_hdr(
421 pim, local_cnt, pim->msdp.originator_id);
422 }
423 }
424
425 if (sa_count) {
426 pim_msdp_pkt_sa_push(pim, mp);
427 }
428 return;
429 }
430
431 static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim)
432 {
433 struct listnode *mpnode;
434 struct pim_msdp_peer *mp;
435
436 /* if SA were sent to the peers we restart ka timer and avoid
437 * unnecessary ka noise */
438 for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
439 if (mp->flags & PIM_MSDP_PEERF_SA_JUST_SENT) {
440 mp->flags &= ~PIM_MSDP_PEERF_SA_JUST_SENT;
441 pim_msdp_peer_pkt_txed(mp);
442 }
443 }
444 }
445
446 void pim_msdp_pkt_sa_tx(struct pim_instance *pim)
447 {
448 pim_msdp_pkt_sa_gen(pim, NULL /* mp */);
449 pim_msdp_pkt_sa_tx_done(pim);
450 }
451
452 void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa)
453 {
454 pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */, sa->rp);
455 pim_msdp_pkt_sa_fill_one(sa);
456 pim_msdp_pkt_sa_push(sa->pim, NULL);
457 pim_msdp_pkt_sa_tx_done(sa->pim);
458 }
459
460 /* when a connection is first established we push all SAs immediately */
461 void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp)
462 {
463 pim_msdp_pkt_sa_gen(mp->pim, mp);
464 pim_msdp_pkt_sa_tx_done(mp->pim);
465 }
466
467 void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp,
468 struct in_addr rp, pim_sgaddr sg)
469 {
470 struct pim_msdp_sa sa;
471
472 /* Fills the SA header. */
473 pim_msdp_pkt_sa_fill_hdr(mp->pim, 1, rp);
474
475 /* Fills the message contents. */
476 sa.pim = mp->pim;
477 sa.sg = sg;
478 pim_msdp_pkt_sa_fill_one(&sa);
479
480 /* Pushes the message. */
481 pim_msdp_pkt_sa_push(sa.pim, mp);
482 pim_msdp_pkt_sa_tx_done(sa.pim);
483 }
484
485 static void pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer *mp)
486 {
487 pim_msdp_peer_reset_tcp_conn(mp, "invalid-pkt-rx");
488 }
489
490 static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len)
491 {
492 mp->ka_rx_cnt++;
493 if (len != PIM_MSDP_KA_TLV_MAX_SIZE) {
494 pim_msdp_pkt_rxed_with_fatal_error(mp);
495 return;
496 }
497 pim_msdp_peer_pkt_rxed(mp);
498 }
499
500 static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
501 {
502 int prefix_len;
503 pim_sgaddr sg;
504 struct listnode *peer_node;
505 struct pim_msdp_peer *peer;
506
507 /* just throw away the three reserved bytes */
508 stream_get3(mp->ibuf);
509 prefix_len = stream_getc(mp->ibuf);
510
511 memset(&sg, 0, sizeof(sg));
512 sg.grp.s_addr = stream_get_ipv4(mp->ibuf);
513 sg.src.s_addr = stream_get_ipv4(mp->ibuf);
514
515 if (prefix_len != IPV4_MAX_BITLEN) {
516 /* ignore SA update if the prefix length is not 32 */
517 flog_err(EC_PIM_MSDP_PACKET,
518 "rxed sa update with invalid prefix length %d",
519 prefix_len);
520 return;
521 }
522 if (PIM_DEBUG_MSDP_PACKETS) {
523 zlog_debug(" sg %pSG", &sg);
524 }
525 pim_msdp_sa_ref(mp->pim, mp, &sg, rp);
526
527 /* Forwards the SA to the peers that are not in the RPF to the RP nor in
528 * the same mesh group as the peer from which we received the message.
529 * If the message group is not set, i.e. "default", then we assume that
530 * the message must be forwarded.*/
531 for (ALL_LIST_ELEMENTS_RO(mp->pim->msdp.peer_list, peer_node, peer)) {
532 /* Not a RPF peer, so skip it. */
533 if (pim_msdp_peer_rpf_check(peer, rp))
534 continue;
535 /* Don't forward inside the meshed group. */
536 if ((mp->flags & PIM_MSDP_PEERF_IN_GROUP)
537 && strcmp(mp->mesh_group_name, peer->mesh_group_name) == 0)
538 continue;
539
540 pim_msdp_pkt_sa_tx_one_to_one_peer(peer, rp, sg);
541 }
542 }
543
544 static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
545 {
546 int entry_cnt;
547 int i;
548 struct in_addr rp; /* Last RP address associated with this SA */
549
550 mp->sa_rx_cnt++;
551
552 if (len < PIM_MSDP_SA_TLV_MIN_SIZE) {
553 pim_msdp_pkt_rxed_with_fatal_error(mp);
554 return;
555 }
556
557 entry_cnt = stream_getc(mp->ibuf);
558 /* some vendors include the actual multicast data in the tlv (at the
559 * end). we will ignore such data. in the future we may consider pushing
560 * it down the RPT
561 */
562 if (len < PIM_MSDP_SA_ENTRY_CNT2SIZE(entry_cnt)) {
563 pim_msdp_pkt_rxed_with_fatal_error(mp);
564 return;
565 }
566 rp.s_addr = stream_get_ipv4(mp->ibuf);
567
568 if (PIM_DEBUG_MSDP_PACKETS) {
569 char rp_str[INET_ADDRSTRLEN];
570 pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
571 zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
572 }
573
574 pim_msdp_peer_pkt_rxed(mp);
575
576 if (!pim_msdp_peer_rpf_check(mp, rp)) {
577 /* if peer-RPF check fails don't process the packet any further
578 */
579 if (PIM_DEBUG_MSDP_PACKETS) {
580 zlog_debug(" peer RPF check failed");
581 }
582 return;
583 }
584
585 /* update SA cache */
586 for (i = 0; i < entry_cnt; ++i) {
587 pim_msdp_pkt_sa_rx_one(mp, rp);
588 }
589 }
590
591 static void pim_msdp_pkt_rx(struct pim_msdp_peer *mp)
592 {
593 enum pim_msdp_tlv type;
594 int len;
595
596 /* re-read type and len */
597 type = stream_getc_from(mp->ibuf, 0);
598 len = stream_getw_from(mp->ibuf, 1);
599 if (len < PIM_MSDP_HEADER_SIZE) {
600 pim_msdp_pkt_rxed_with_fatal_error(mp);
601 return;
602 }
603
604 if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
605 /* if tlv size if greater than max just ignore the tlv */
606 return;
607 }
608
609 if (PIM_DEBUG_MSDP_PACKETS) {
610 pim_msdp_pkt_dump(mp, type, len, true /*rx*/, NULL /*s*/);
611 }
612
613 switch (type) {
614 case PIM_MSDP_KEEPALIVE:
615 pim_msdp_pkt_ka_rx(mp, len);
616 break;
617 case PIM_MSDP_V4_SOURCE_ACTIVE:
618 mp->sa_rx_cnt++;
619 pim_msdp_pkt_sa_rx(mp, len);
620 break;
621 case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST:
622 case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE:
623 case PIM_MSDP_RESERVED:
624 case PIM_MSDP_TRACEROUTE_PROGRESS:
625 case PIM_MSDP_TRACEROUTE_REPLY:
626 mp->unk_rx_cnt++;
627 break;
628 }
629 }
630
631 /* pim msdp read utility function. */
632 static int pim_msdp_read_packet(struct pim_msdp_peer *mp)
633 {
634 int nbytes;
635 int readsize;
636 int old_endp;
637 int new_endp;
638
639 old_endp = stream_get_endp(mp->ibuf);
640 readsize = mp->packet_size - old_endp;
641 if (!readsize) {
642 return 0;
643 }
644
645 /* Read packet from fd */
646 nbytes = stream_read_try(mp->ibuf, mp->fd, readsize);
647 new_endp = stream_get_endp(mp->ibuf);
648 if (nbytes < 0) {
649 if (PIM_DEBUG_MSDP_INTERNAL) {
650 zlog_debug("MSDP peer %s read failed %d", mp->key_str,
651 nbytes);
652 }
653 if (nbytes == -2) {
654 if (PIM_DEBUG_MSDP_INTERNAL) {
655 zlog_debug(
656 "MSDP peer %s pim_msdp_read io retry old_end: %d new_end: %d",
657 mp->key_str, old_endp, new_endp);
658 }
659 /* transient error retry */
660 return -1;
661 }
662 pim_msdp_pkt_rxed_with_fatal_error(mp);
663 return -1;
664 }
665
666 if (!nbytes) {
667 if (PIM_DEBUG_MSDP_INTERNAL) {
668 zlog_debug("MSDP peer %s read failed %d", mp->key_str,
669 nbytes);
670 }
671 pim_msdp_peer_reset_tcp_conn(mp, "peer-down");
672 return -1;
673 }
674
675 /* We read partial packet. */
676 if (stream_get_endp(mp->ibuf) != mp->packet_size) {
677 if (PIM_DEBUG_MSDP_INTERNAL) {
678 zlog_debug(
679 "MSDP peer %s read partial len %d old_endp %d new_endp %d",
680 mp->key_str, mp->packet_size, old_endp,
681 new_endp);
682 }
683 return -1;
684 }
685
686 return 0;
687 }
688
689 void pim_msdp_read(struct thread *thread)
690 {
691 struct pim_msdp_peer *mp;
692 int rc;
693 uint32_t len;
694
695 mp = THREAD_ARG(thread);
696 mp->t_read = NULL;
697
698 if (PIM_DEBUG_MSDP_INTERNAL) {
699 zlog_debug("MSDP peer %s pim_msdp_read", mp->key_str);
700 }
701
702 if (mp->fd < 0) {
703 return;
704 }
705
706 /* check if TCP connection is established */
707 if (mp->state != PIM_MSDP_ESTABLISHED) {
708 pim_msdp_connect_check(mp);
709 return;
710 }
711
712 PIM_MSDP_PEER_READ_ON(mp);
713
714 if (!mp->packet_size) {
715 mp->packet_size = PIM_MSDP_HEADER_SIZE;
716 }
717
718 if (stream_get_endp(mp->ibuf) < PIM_MSDP_HEADER_SIZE) {
719 /* start by reading the TLV header */
720 rc = pim_msdp_read_packet(mp);
721 if (rc < 0)
722 return;
723
724 /* Find TLV type and len */
725 stream_getc(mp->ibuf);
726 len = stream_getw(mp->ibuf);
727 if (len < PIM_MSDP_HEADER_SIZE) {
728 pim_msdp_pkt_rxed_with_fatal_error(mp);
729 return;
730 }
731
732 /*
733 * Handle messages with longer than expected TLV size: resize
734 * the stream to handle reading the whole message.
735 *
736 * RFC 3618 Section 12. 'Packet Formats':
737 * > ... If an implementation receives a TLV whose length
738 * > exceeds the maximum TLV length specified below, the TLV
739 * > SHOULD be accepted. Any additional data, including possible
740 * > next TLV's in the same message, SHOULD be ignored, and the
741 * > MSDP session should not be reset. ...
742 */
743 if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
744 /* Check if the current buffer is big enough. */
745 if (mp->ibuf->size < len) {
746 if (PIM_DEBUG_MSDP_PACKETS)
747 zlog_debug(
748 "MSDP peer %s sent TLV with unexpected large length (%d bytes)",
749 mp->key_str, len);
750
751 stream_resize_inplace(&mp->ibuf, len);
752 }
753 }
754
755 /* read complete TLV */
756 mp->packet_size = len;
757 }
758
759 rc = pim_msdp_read_packet(mp);
760 if (rc < 0)
761 return;
762
763 pim_msdp_pkt_rx(mp);
764
765 /* reset input buffers and get ready for the next packet */
766 mp->packet_size = 0;
767 stream_reset(mp->ibuf);
768 }