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