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