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