]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_msdp_packet.c
bgpd: fix the IGP metric for best path selection on VPN import
[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"
993e3d8e 29#include "pim_instance.h"
2a333e0f 30#include "pim_str.h"
d9ff4302 31#include "pim_errors.h"
2a333e0f 32
33#include "pim_msdp.h"
34#include "pim_msdp_packet.h"
35#include "pim_msdp_socket.h"
36
d62a17ae 37static char *pim_msdp_pkt_type_dump(enum pim_msdp_tlv type, char *buf,
38 int buf_size)
2a333e0f 39{
d62a17ae 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;
2a333e0f 66}
67
d62a17ae 68static void pim_msdp_pkt_sa_dump_one(struct stream *s)
15ad0c71 69{
6fff2cc6 70 pim_sgaddr sg;
15ad0c71 71
d62a17ae 72 /* just throw away the three reserved bytes */
73 stream_get3(s);
74 /* throw away the prefix length also */
75 stream_getc(s);
15ad0c71 76
6fff2cc6 77 memset(&sg, 0, sizeof(sg));
d62a17ae 78 sg.grp.s_addr = stream_get_ipv4(s);
79 sg.src.s_addr = stream_get_ipv4(s);
15ad0c71 80
98a81d2b 81 zlog_debug(" sg %pSG", &sg);
15ad0c71 82}
83
d62a17ae 84static void pim_msdp_pkt_sa_dump(struct stream *s)
15ad0c71 85{
1dd422a2
RZ
86 const size_t header_length = PIM_MSDP_SA_X_SIZE - PIM_MSDP_HEADER_SIZE;
87 size_t payload_length;
d62a17ae 88 int entry_cnt;
89 int i;
90 struct in_addr rp; /* Last RP address associated with this SA */
91
1dd422a2
RZ
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
d62a17ae 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
1dd422a2
RZ
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
d62a17ae 114 /* dump SAs */
115 for (i = 0; i < entry_cnt; ++i) {
116 pim_msdp_pkt_sa_dump_one(s);
117 }
15ad0c71 118}
119
d62a17ae 120static void pim_msdp_pkt_dump(struct pim_msdp_peer *mp, int type, int len,
121 bool rx, struct stream *s)
2a333e0f 122{
d62a17ae 123 char type_str[PIM_MSDP_PKT_TYPE_STRLEN];
2a333e0f 124
d62a17ae 125 pim_msdp_pkt_type_dump(type, type_str, sizeof(type_str));
2a333e0f 126
d62a17ae 127 zlog_debug("MSDP peer %s pkt %s type %s len %d", mp->key_str,
128 rx ? "rx" : "tx", type_str, len);
15ad0c71 129
d62a17ae 130 if (!s) {
131 return;
132 }
15ad0c71 133
1dd422a2
RZ
134 if (len < PIM_MSDP_HEADER_SIZE) {
135 zlog_err("invalid MSDP header length");
136 return;
137 }
138
d62a17ae 139 switch (type) {
140 case PIM_MSDP_V4_SOURCE_ACTIVE:
141 pim_msdp_pkt_sa_dump(s);
142 break;
143 default:;
144 }
2a333e0f 145}
146
147/* Check file descriptor whether connect is established. */
d62a17ae 148static void pim_msdp_connect_check(struct pim_msdp_peer *mp)
2a333e0f 149{
d62a17ae 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) {
450971aa 171 flog_err_sys(EC_LIB_SOCKET,
09c866e3 172 "can't get sockopt for nonblocking connect");
d62a17ae 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 }
2a333e0f 187}
188
d62a17ae 189static void pim_msdp_pkt_delete(struct pim_msdp_peer *mp)
2a333e0f 190{
d62a17ae 191 stream_free(stream_fifo_pop(mp->obuf));
2a333e0f 192}
193
d62a17ae 194static void pim_msdp_pkt_add(struct pim_msdp_peer *mp, struct stream *s)
3c72d654 195{
d62a17ae 196 stream_fifo_push(mp->obuf, s);
3c72d654 197}
198
d62a17ae 199static void pim_msdp_write_proceed_actions(struct pim_msdp_peer *mp)
2a333e0f 200{
d62a17ae 201 if (stream_fifo_head(mp->obuf)) {
202 PIM_MSDP_PEER_WRITE_ON(mp);
203 }
2a333e0f 204}
205
cc9f21da 206void pim_msdp_write(struct thread *thread)
2a333e0f 207{
d62a17ae 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) {
cc9f21da 223 return;
d62a17ae 224 }
225
226 /* check if TCP connection is established */
227 if (mp->state != PIM_MSDP_ESTABLISHED) {
228 pim_msdp_connect_check(mp);
cc9f21da 229 return;
d62a17ae 230 }
231
232 s = stream_fifo_head(mp->obuf);
233 if (!s) {
234 pim_msdp_write_proceed_actions(mp);
cc9f21da 235 return;
d62a17ae 236 }
237
d62a17ae 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 */
2d34fb80 246 num = write(mp->fd, stream_pnt(s), writenum);
d62a17ae 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");
cc9f21da 259 return;
d62a17ae 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 default:;
285 }
286 if (PIM_DEBUG_MSDP_PACKETS) {
287 pim_msdp_pkt_dump(mp, type, len, false /*rx*/, s);
288 }
289
290 /* packet sent delete it. */
291 pim_msdp_pkt_delete(mp);
292
293 ++work_cnt;
294 /* may need to pause if we have done too much work in this
295 * loop */
296 if (work_cnt >= work_max_cnt) {
297 break;
298 }
299 } while ((s = stream_fifo_head(mp->obuf)) != NULL);
300 pim_msdp_write_proceed_actions(mp);
301
d62a17ae 302 if (PIM_DEBUG_MSDP_INTERNAL) {
303 zlog_debug("MSDP peer %s pim_msdp_write wrote %d packets",
304 mp->key_str, work_cnt);
305 }
2a333e0f 306}
307
d62a17ae 308static void pim_msdp_pkt_send(struct pim_msdp_peer *mp, struct stream *s)
2a333e0f 309{
d62a17ae 310 /* Add packet to the end of list. */
311 pim_msdp_pkt_add(mp, s);
2a333e0f 312
d62a17ae 313 PIM_MSDP_PEER_WRITE_ON(mp);
2a333e0f 314}
315
d62a17ae 316void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp)
2a333e0f 317{
d62a17ae 318 struct stream *s;
2a333e0f 319
d62a17ae 320 if (mp->state != PIM_MSDP_ESTABLISHED) {
321 /* don't tx anything unless a session is established */
322 return;
323 }
324 s = stream_new(PIM_MSDP_KA_TLV_MAX_SIZE);
325 stream_putc(s, PIM_MSDP_KEEPALIVE);
326 stream_putw(s, PIM_MSDP_KA_TLV_MAX_SIZE);
2a333e0f 327
d62a17ae 328 pim_msdp_pkt_send(mp, s);
2a333e0f 329}
330
10c899e2
DS
331static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim,
332 struct pim_msdp_peer *mp)
3c72d654 333{
d62a17ae 334 struct stream *s;
335
336 if (mp->state != PIM_MSDP_ESTABLISHED) {
337 /* don't tx anything unless a session is established */
338 return;
339 }
10c899e2 340 s = stream_dup(pim->msdp.work_obuf);
d62a17ae 341 if (s) {
342 pim_msdp_pkt_send(mp, s);
343 mp->flags |= PIM_MSDP_PEERF_SA_JUST_SENT;
344 }
3c72d654 345}
346
347/* push the stream into the obuf fifo of all the peers */
10c899e2
DS
348static void pim_msdp_pkt_sa_push(struct pim_instance *pim,
349 struct pim_msdp_peer *mp)
3c72d654 350{
d62a17ae 351 struct listnode *mpnode;
352
353 if (mp) {
10c899e2 354 pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
d62a17ae 355 } else {
10c899e2 356 for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
d62a17ae 357 if (PIM_DEBUG_MSDP_INTERNAL) {
358 zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push",
359 mp->key_str);
360 }
10c899e2 361 pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
d62a17ae 362 }
363 }
3c72d654 364}
365
9fbd9fc4
AMR
366static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt,
367 struct in_addr rp)
3c72d654 368{
d62a17ae 369 int curr_tlv_ecnt;
370
472ad383 371 stream_reset(pim->msdp.work_obuf);
d62a17ae 372 curr_tlv_ecnt = local_cnt > PIM_MSDP_SA_MAX_ENTRY_CNT
373 ? PIM_MSDP_SA_MAX_ENTRY_CNT
374 : local_cnt;
375 local_cnt -= curr_tlv_ecnt;
472ad383
DS
376 stream_putc(pim->msdp.work_obuf, PIM_MSDP_V4_SOURCE_ACTIVE);
377 stream_putw(pim->msdp.work_obuf,
2ad78035 378 PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt));
472ad383 379 stream_putc(pim->msdp.work_obuf, curr_tlv_ecnt);
9fbd9fc4 380 stream_put_ipv4(pim->msdp.work_obuf, rp.s_addr);
d62a17ae 381
382 return local_cnt;
3c72d654 383}
384
d62a17ae 385static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa)
3c72d654 386{
472ad383
DS
387 stream_put3(sa->pim->msdp.work_obuf, 0 /* reserved */);
388 stream_putc(sa->pim->msdp.work_obuf, 32 /* sprefix len */);
389 stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.grp.s_addr);
390 stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr);
3c72d654 391}
392
4097373f
DS
393static void pim_msdp_pkt_sa_gen(struct pim_instance *pim,
394 struct pim_msdp_peer *mp)
3c72d654 395{
d62a17ae 396 struct listnode *sanode;
397 struct pim_msdp_sa *sa;
398 int sa_count;
4097373f 399 int local_cnt = pim->msdp.local_cnt;
d62a17ae 400
401 sa_count = 0;
402 if (PIM_DEBUG_MSDP_INTERNAL) {
403 zlog_debug(" sa gen %d", local_cnt);
404 }
405
9fbd9fc4
AMR
406 local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt,
407 pim->msdp.originator_id);
d62a17ae 408
4097373f 409 for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
d62a17ae 410 if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
411 /* current implementation of MSDP is for anycast i.e.
412 * full mesh. so
413 * no re-forwarding of SAs that we learnt from other
414 * peers */
415 continue;
416 }
417 /* add sa into scratch pad */
418 pim_msdp_pkt_sa_fill_one(sa);
419 ++sa_count;
420 if (sa_count >= PIM_MSDP_SA_MAX_ENTRY_CNT) {
10c899e2 421 pim_msdp_pkt_sa_push(pim, mp);
d62a17ae 422 /* reset headers */
423 sa_count = 0;
424 if (PIM_DEBUG_MSDP_INTERNAL) {
425 zlog_debug(" sa gen for remainder %d",
426 local_cnt);
427 }
9fbd9fc4
AMR
428 local_cnt = pim_msdp_pkt_sa_fill_hdr(
429 pim, local_cnt, pim->msdp.originator_id);
d62a17ae 430 }
431 }
432
433 if (sa_count) {
10c899e2 434 pim_msdp_pkt_sa_push(pim, mp);
d62a17ae 435 }
436 return;
3c72d654 437}
438
472ad383 439static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim)
3c72d654 440{
d62a17ae 441 struct listnode *mpnode;
442 struct pim_msdp_peer *mp;
443
444 /* if SA were sent to the peers we restart ka timer and avoid
445 * unnecessary ka noise */
472ad383 446 for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
d62a17ae 447 if (mp->flags & PIM_MSDP_PEERF_SA_JUST_SENT) {
448 mp->flags &= ~PIM_MSDP_PEERF_SA_JUST_SENT;
449 pim_msdp_peer_pkt_txed(mp);
450 }
451 }
3c72d654 452}
453
472ad383 454void pim_msdp_pkt_sa_tx(struct pim_instance *pim)
3c72d654 455{
4097373f 456 pim_msdp_pkt_sa_gen(pim, NULL /* mp */);
472ad383 457 pim_msdp_pkt_sa_tx_done(pim);
3c72d654 458}
459
d62a17ae 460void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa)
3c72d654 461{
9fbd9fc4 462 pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */, sa->rp);
d62a17ae 463 pim_msdp_pkt_sa_fill_one(sa);
10c899e2 464 pim_msdp_pkt_sa_push(sa->pim, NULL);
472ad383 465 pim_msdp_pkt_sa_tx_done(sa->pim);
3c72d654 466}
467
468/* when a connection is first established we push all SAs immediately */
d62a17ae 469void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp)
3c72d654 470{
4097373f 471 pim_msdp_pkt_sa_gen(mp->pim, mp);
472ad383 472 pim_msdp_pkt_sa_tx_done(mp->pim);
3c72d654 473}
474
9fbd9fc4 475void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp,
6fff2cc6 476 struct in_addr rp, pim_sgaddr sg)
9fbd9fc4
AMR
477{
478 struct pim_msdp_sa sa;
479
480 /* Fills the SA header. */
481 pim_msdp_pkt_sa_fill_hdr(mp->pim, 1, rp);
482
483 /* Fills the message contents. */
484 sa.pim = mp->pim;
485 sa.sg = sg;
486 pim_msdp_pkt_sa_fill_one(&sa);
487
488 /* Pushes the message. */
489 pim_msdp_pkt_sa_push(sa.pim, mp);
490 pim_msdp_pkt_sa_tx_done(sa.pim);
491}
492
d62a17ae 493static void pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer *mp)
2a333e0f 494{
d62a17ae 495 pim_msdp_peer_reset_tcp_conn(mp, "invalid-pkt-rx");
2a333e0f 496}
497
d62a17ae 498static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len)
2a333e0f 499{
d62a17ae 500 mp->ka_rx_cnt++;
501 if (len != PIM_MSDP_KA_TLV_MAX_SIZE) {
502 pim_msdp_pkt_rxed_with_fatal_error(mp);
503 return;
504 }
505 pim_msdp_peer_pkt_rxed(mp);
2a333e0f 506}
507
d62a17ae 508static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
3c72d654 509{
d62a17ae 510 int prefix_len;
6fff2cc6 511 pim_sgaddr sg;
9fbd9fc4
AMR
512 struct listnode *peer_node;
513 struct pim_msdp_peer *peer;
d62a17ae 514
515 /* just throw away the three reserved bytes */
516 stream_get3(mp->ibuf);
517 prefix_len = stream_getc(mp->ibuf);
518
6fff2cc6 519 memset(&sg, 0, sizeof(sg));
d62a17ae 520 sg.grp.s_addr = stream_get_ipv4(mp->ibuf);
521 sg.src.s_addr = stream_get_ipv4(mp->ibuf);
522
12256b84 523 if (prefix_len != IPV4_MAX_BITLEN) {
d62a17ae 524 /* ignore SA update if the prefix length is not 32 */
298004a1 525 flog_err(EC_PIM_MSDP_PACKET,
1c50c1c0
QY
526 "rxed sa update with invalid prefix length %d",
527 prefix_len);
d62a17ae 528 return;
529 }
530 if (PIM_DEBUG_MSDP_PACKETS) {
98a81d2b 531 zlog_debug(" sg %pSG", &sg);
d62a17ae 532 }
472ad383 533 pim_msdp_sa_ref(mp->pim, mp, &sg, rp);
9fbd9fc4
AMR
534
535 /* Forwards the SA to the peers that are not in the RPF to the RP nor in
536 * the same mesh group as the peer from which we received the message.
537 * If the message group is not set, i.e. "default", then we assume that
538 * the message must be forwarded.*/
539 for (ALL_LIST_ELEMENTS_RO(mp->pim->msdp.peer_list, peer_node, peer)) {
0ce04a08
RZ
540 /* Not a RPF peer, so skip it. */
541 if (pim_msdp_peer_rpf_check(peer, rp))
542 continue;
543 /* Don't forward inside the meshed group. */
544 if ((mp->flags & PIM_MSDP_PEERF_IN_GROUP)
545 && strcmp(mp->mesh_group_name, peer->mesh_group_name) == 0)
546 continue;
547
548 pim_msdp_pkt_sa_tx_one_to_one_peer(peer, rp, sg);
9fbd9fc4 549 }
3c72d654 550}
551
d62a17ae 552static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
2a333e0f 553{
d62a17ae 554 int entry_cnt;
555 int i;
556 struct in_addr rp; /* Last RP address associated with this SA */
557
558 mp->sa_rx_cnt++;
559
560 if (len < PIM_MSDP_SA_TLV_MIN_SIZE) {
561 pim_msdp_pkt_rxed_with_fatal_error(mp);
562 return;
563 }
564
565 entry_cnt = stream_getc(mp->ibuf);
566 /* some vendors include the actual multicast data in the tlv (at the
9fbd9fc4
AMR
567 * end). we will ignore such data. in the future we may consider pushing
568 * it down the RPT
569 */
d62a17ae 570 if (len < PIM_MSDP_SA_ENTRY_CNT2SIZE(entry_cnt)) {
571 pim_msdp_pkt_rxed_with_fatal_error(mp);
572 return;
573 }
574 rp.s_addr = stream_get_ipv4(mp->ibuf);
575
576 if (PIM_DEBUG_MSDP_PACKETS) {
577 char rp_str[INET_ADDRSTRLEN];
578 pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
579 zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
580 }
581
9fbd9fc4
AMR
582 pim_msdp_peer_pkt_rxed(mp);
583
d62a17ae 584 if (!pim_msdp_peer_rpf_check(mp, rp)) {
585 /* if peer-RPF check fails don't process the packet any further
586 */
587 if (PIM_DEBUG_MSDP_PACKETS) {
588 zlog_debug(" peer RPF check failed");
589 }
590 return;
591 }
592
d62a17ae 593 /* update SA cache */
594 for (i = 0; i < entry_cnt; ++i) {
595 pim_msdp_pkt_sa_rx_one(mp, rp);
596 }
2a333e0f 597}
598
d62a17ae 599static void pim_msdp_pkt_rx(struct pim_msdp_peer *mp)
2a333e0f 600{
d62a17ae 601 enum pim_msdp_tlv type;
602 int len;
603
604 /* re-read type and len */
605 type = stream_getc_from(mp->ibuf, 0);
606 len = stream_getw_from(mp->ibuf, 1);
607 if (len < PIM_MSDP_HEADER_SIZE) {
608 pim_msdp_pkt_rxed_with_fatal_error(mp);
609 return;
610 }
611
612 if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
613 /* if tlv size if greater than max just ignore the tlv */
614 return;
615 }
616
617 if (PIM_DEBUG_MSDP_PACKETS) {
618 pim_msdp_pkt_dump(mp, type, len, true /*rx*/, NULL /*s*/);
619 }
620
621 switch (type) {
622 case PIM_MSDP_KEEPALIVE:
623 pim_msdp_pkt_ka_rx(mp, len);
624 break;
625 case PIM_MSDP_V4_SOURCE_ACTIVE:
626 mp->sa_rx_cnt++;
627 pim_msdp_pkt_sa_rx(mp, len);
628 break;
629 default:
630 mp->unk_rx_cnt++;
631 }
2a333e0f 632}
633
634/* pim msdp read utility function. */
d62a17ae 635static int pim_msdp_read_packet(struct pim_msdp_peer *mp)
2a333e0f 636{
d62a17ae 637 int nbytes;
638 int readsize;
639 int old_endp;
640 int new_endp;
641
642 old_endp = stream_get_endp(mp->ibuf);
643 readsize = mp->packet_size - old_endp;
644 if (!readsize) {
645 return 0;
646 }
647
648 /* Read packet from fd */
649 nbytes = stream_read_try(mp->ibuf, mp->fd, readsize);
650 new_endp = stream_get_endp(mp->ibuf);
651 if (nbytes < 0) {
652 if (PIM_DEBUG_MSDP_INTERNAL) {
653 zlog_debug("MSDP peer %s read failed %d", mp->key_str,
654 nbytes);
655 }
656 if (nbytes == -2) {
657 if (PIM_DEBUG_MSDP_INTERNAL) {
658 zlog_debug(
659 "MSDP peer %s pim_msdp_read io retry old_end: %d new_end: %d",
660 mp->key_str, old_endp, new_endp);
661 }
662 /* transient error retry */
663 return -1;
664 }
665 pim_msdp_pkt_rxed_with_fatal_error(mp);
666 return -1;
667 }
668
669 if (!nbytes) {
670 if (PIM_DEBUG_MSDP_INTERNAL) {
671 zlog_debug("MSDP peer %s read failed %d", mp->key_str,
672 nbytes);
673 }
674 pim_msdp_peer_reset_tcp_conn(mp, "peer-down");
675 return -1;
676 }
677
678 /* We read partial packet. */
679 if (stream_get_endp(mp->ibuf) != mp->packet_size) {
680 if (PIM_DEBUG_MSDP_INTERNAL) {
681 zlog_debug(
682 "MSDP peer %s read partial len %d old_endp %d new_endp %d",
683 mp->key_str, mp->packet_size, old_endp,
684 new_endp);
685 }
686 return -1;
687 }
688
689 return 0;
2a333e0f 690}
691
cc9f21da 692void pim_msdp_read(struct thread *thread)
2a333e0f 693{
d62a17ae 694 struct pim_msdp_peer *mp;
695 int rc;
696 uint32_t len;
697
698 mp = THREAD_ARG(thread);
699 mp->t_read = NULL;
700
701 if (PIM_DEBUG_MSDP_INTERNAL) {
702 zlog_debug("MSDP peer %s pim_msdp_read", mp->key_str);
703 }
704
705 if (mp->fd < 0) {
cc9f21da 706 return;
d62a17ae 707 }
708
709 /* check if TCP connection is established */
710 if (mp->state != PIM_MSDP_ESTABLISHED) {
711 pim_msdp_connect_check(mp);
cc9f21da 712 return;
d62a17ae 713 }
714
715 PIM_MSDP_PEER_READ_ON(mp);
716
717 if (!mp->packet_size) {
718 mp->packet_size = PIM_MSDP_HEADER_SIZE;
719 }
720
721 if (stream_get_endp(mp->ibuf) < PIM_MSDP_HEADER_SIZE) {
722 /* start by reading the TLV header */
723 rc = pim_msdp_read_packet(mp);
cc9f21da
DS
724 if (rc < 0)
725 return;
d62a17ae 726
727 /* Find TLV type and len */
728 stream_getc(mp->ibuf);
729 len = stream_getw(mp->ibuf);
730 if (len < PIM_MSDP_HEADER_SIZE) {
731 pim_msdp_pkt_rxed_with_fatal_error(mp);
cc9f21da 732 return;
d62a17ae 733 }
d4981032
RZ
734
735 /*
736 * Handle messages with longer than expected TLV size: resize
737 * the stream to handle reading the whole message.
738 *
739 * RFC 3618 Section 12. 'Packet Formats':
740 * > ... If an implementation receives a TLV whose length
741 * > exceeds the maximum TLV length specified below, the TLV
742 * > SHOULD be accepted. Any additional data, including possible
743 * > next TLV's in the same message, SHOULD be ignored, and the
744 * > MSDP session should not be reset. ...
745 */
746 if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
747 /* Check if the current buffer is big enough. */
748 if (mp->ibuf->size < len) {
749 if (PIM_DEBUG_MSDP_PACKETS)
750 zlog_debug(
751 "MSDP peer %s sent TLV with unexpected large length (%d bytes)",
752 mp->key_str, len);
753
754 stream_resize_inplace(&mp->ibuf, len);
755 }
756 }
757
d62a17ae 758 /* read complete TLV */
759 mp->packet_size = len;
760 }
761
762 rc = pim_msdp_read_packet(mp);
cc9f21da
DS
763 if (rc < 0)
764 return;
d62a17ae 765
766 pim_msdp_pkt_rx(mp);
767
768 /* reset input buffers and get ready for the next packet */
769 mp->packet_size = 0;
770 stream_reset(mp->ibuf);
2a333e0f 771}