1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2008 Everton da Silva Marques
16 #include "pim_instance.h"
19 #include "pim_iface.h"
24 #include "pim_neighbor.h"
25 #include "pim_hello.h"
27 #include "pim_assert.h"
29 #include "pim_register.h"
30 #include "pim_errors.h"
32 #include <lib/lib_errors.h>
34 static void on_pim_hello_send(struct event
*t
);
36 static const char *pim_pim_msgtype2str(enum pim_msg_type type
)
39 case PIM_MSG_TYPE_HELLO
:
41 case PIM_MSG_TYPE_REGISTER
:
43 case PIM_MSG_TYPE_REG_STOP
:
45 case PIM_MSG_TYPE_JOIN_PRUNE
:
47 case PIM_MSG_TYPE_BOOTSTRAP
:
49 case PIM_MSG_TYPE_ASSERT
:
51 case PIM_MSG_TYPE_GRAFT
:
53 case PIM_MSG_TYPE_GRAFT_ACK
:
55 case PIM_MSG_TYPE_CANDIDATE
:
62 static void sock_close(struct interface
*ifp
)
64 struct pim_interface
*pim_ifp
= ifp
->info
;
66 if (PIM_DEBUG_PIM_TRACE
) {
67 if (pim_ifp
->t_pim_sock_read
) {
69 "Cancelling READ event for PIM socket fd=%d on interface %s",
70 pim_ifp
->pim_sock_fd
, ifp
->name
);
73 EVENT_OFF(pim_ifp
->t_pim_sock_read
);
75 if (PIM_DEBUG_PIM_TRACE
) {
76 if (pim_ifp
->t_pim_hello_timer
) {
78 "Cancelling PIM hello timer for interface %s",
82 EVENT_OFF(pim_ifp
->t_pim_hello_timer
);
84 if (PIM_DEBUG_PIM_TRACE
) {
85 zlog_debug("Deleting PIM socket fd=%d on interface %s",
86 pim_ifp
->pim_sock_fd
, ifp
->name
);
90 * If the fd is already deleted no need to do anything here
92 if (pim_ifp
->pim_sock_fd
> 0 && close(pim_ifp
->pim_sock_fd
)) {
94 "Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
95 pim_ifp
->pim_sock_fd
, ifp
->name
, errno
,
96 safe_strerror(errno
));
99 pim_ifp
->pim_sock_fd
= -1;
100 pim_ifp
->pim_sock_creation
= 0;
103 void pim_sock_delete(struct interface
*ifp
, const char *delete_message
)
105 zlog_info("PIM INTERFACE DOWN: on interface %s: %s", ifp
->name
,
109 flog_err(EC_PIM_CONFIG
,
110 "%s: %s: but PIM not enabled on interface %s (!)",
111 __func__
, delete_message
, ifp
->name
);
116 RFC 4601: 4.3.1. Sending Hello Messages
118 Before an interface goes down or changes primary IP address, a Hello
119 message with a zero HoldTime should be sent immediately (with the
120 old IP address if the IP address changed).
122 pim_hello_send(ifp
, 0 /* zero-sec holdtime */);
124 pim_neighbor_delete_all(ifp
, delete_message
);
129 /* For now check dst address for hello, assrt and join/prune is all pim rtr */
130 static bool pim_pkt_dst_addr_ok(enum pim_msg_type type
, pim_addr addr
)
132 if ((type
== PIM_MSG_TYPE_HELLO
) || (type
== PIM_MSG_TYPE_ASSERT
)
133 || (type
== PIM_MSG_TYPE_JOIN_PRUNE
)) {
134 if (pim_addr_cmp(addr
, qpim_all_pim_routers_addr
))
141 int pim_pim_packet(struct interface
*ifp
, uint8_t *buf
, size_t len
,
144 struct iovec iov
[2], *iovp
= iov
;
146 struct ip
*ip_hdr
= (struct ip
*)buf
;
147 size_t ip_hlen
; /* ip header length in bytes */
150 uint32_t pim_msg_len
= 0;
151 uint16_t pim_checksum
; /* received checksum */
152 uint16_t checksum
; /* computed checksum */
153 struct pim_neighbor
*neigh
;
154 struct pim_msg_header
*header
;
158 if (len
< sizeof(*ip_hdr
)) {
159 if (PIM_DEBUG_PIM_PACKETS
)
161 "PIM packet size=%zu shorter than minimum=%zu",
162 len
, sizeof(*ip_hdr
));
166 ip_hlen
= ip_hdr
->ip_hl
<< 2; /* ip_hl gives length in 4-byte words */
167 sg
= pim_sgaddr_from_iphdr(ip_hdr
);
169 pim_msg
= buf
+ ip_hlen
;
170 pim_msg_len
= len
- ip_hlen
;
172 struct ipv6_ph phdr
= {
176 .next_hdr
= IPPROTO_PIM
,
179 iovp
->iov_base
= &phdr
;
180 iovp
->iov_len
= sizeof(phdr
);
183 /* NB: header is not included in IPv6 RX */
188 iovp
->iov_base
= pim_msg
;
189 iovp
->iov_len
= pim_msg_len
;
192 header
= (struct pim_msg_header
*)pim_msg
;
193 if (pim_msg_len
< PIM_PIM_MIN_LEN
) {
194 if (PIM_DEBUG_PIM_PACKETS
)
196 "PIM message size=%d shorter than minimum=%d",
197 pim_msg_len
, PIM_PIM_MIN_LEN
);
201 if (header
->ver
!= PIM_PROTO_VERSION
) {
202 if (PIM_DEBUG_PIM_PACKETS
)
204 "Ignoring PIM pkt from %s with unsupported version: %d",
205 ifp
->name
, header
->ver
);
209 /* save received checksum */
210 pim_checksum
= header
->checksum
;
212 /* for computing checksum */
213 header
->checksum
= 0;
214 no_fwd
= header
->Nbit
;
216 if (header
->type
== PIM_MSG_TYPE_REGISTER
) {
217 if (pim_msg_len
< PIM_MSG_REGISTER_LEN
) {
218 if (PIM_DEBUG_PIM_PACKETS
)
219 zlog_debug("PIM Register Message size=%d shorther than min length %d",
220 pim_msg_len
, PIM_MSG_REGISTER_LEN
);
225 phdr
.ulpl
= htonl(PIM_MSG_REGISTER_LEN
);
227 /* First 8 byte header checksum */
228 iovp
[-1].iov_len
= PIM_MSG_REGISTER_LEN
;
229 checksum
= in_cksumv(iov
, iovp
- iov
);
231 if (checksum
!= pim_checksum
) {
233 phdr
.ulpl
= htonl(pim_msg_len
);
235 iovp
[-1].iov_len
= pim_msg_len
;
237 checksum
= in_cksumv(iov
, iovp
- iov
);
238 if (checksum
!= pim_checksum
) {
239 if (PIM_DEBUG_PIM_PACKETS
)
241 "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
242 ifp
->name
, pim_checksum
,
249 checksum
= in_cksumv(iov
, iovp
- iov
);
250 if (checksum
!= pim_checksum
) {
251 if (PIM_DEBUG_PIM_PACKETS
)
253 "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
254 ifp
->name
, pim_checksum
, checksum
);
260 if (PIM_DEBUG_PIM_PACKETS
) {
262 "Recv PIM %s packet from %pPA to %pPA on %s: pim_version=%d pim_msg_size=%d checksum=%x",
263 pim_pim_msgtype2str(header
->type
), &sg
.src
, &sg
.grp
,
264 ifp
->name
, header
->ver
, pim_msg_len
, checksum
);
265 if (PIM_DEBUG_PIM_PACKETDUMP_RECV
)
266 pim_pkt_dump(__func__
, pim_msg
, pim_msg_len
);
269 if (!pim_pkt_dst_addr_ok(header
->type
, sg
.grp
)) {
271 "%s: Ignoring Pkt. Unexpected IP destination %pPA for %s (Expected: all_pim_routers_addr) from %pPA",
272 __func__
, &sg
.grp
, pim_pim_msgtype2str(header
->type
),
277 switch (header
->type
) {
278 case PIM_MSG_TYPE_HELLO
:
279 return pim_hello_recv(ifp
, sg
.src
, pim_msg
+ PIM_MSG_HEADER_LEN
,
280 pim_msg_len
- PIM_MSG_HEADER_LEN
);
282 case PIM_MSG_TYPE_REGISTER
:
283 return pim_register_recv(ifp
, sg
.grp
, sg
.src
,
284 pim_msg
+ PIM_MSG_HEADER_LEN
,
285 pim_msg_len
- PIM_MSG_HEADER_LEN
);
287 case PIM_MSG_TYPE_REG_STOP
:
288 return pim_register_stop_recv(ifp
, pim_msg
+ PIM_MSG_HEADER_LEN
,
289 pim_msg_len
- PIM_MSG_HEADER_LEN
);
291 case PIM_MSG_TYPE_JOIN_PRUNE
:
292 neigh
= pim_neighbor_find(ifp
, sg
.src
, false);
294 if (PIM_DEBUG_PIM_PACKETS
)
296 "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
297 __FILE__
, __func__
, header
->type
,
301 pim_neighbor_timer_reset(neigh
, neigh
->holdtime
);
302 return pim_joinprune_recv(ifp
, neigh
, sg
.src
,
303 pim_msg
+ PIM_MSG_HEADER_LEN
,
304 pim_msg_len
- PIM_MSG_HEADER_LEN
);
306 case PIM_MSG_TYPE_ASSERT
:
307 neigh
= pim_neighbor_find(ifp
, sg
.src
, false);
309 if (PIM_DEBUG_PIM_PACKETS
)
311 "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
312 __FILE__
, __func__
, header
->type
,
316 pim_neighbor_timer_reset(neigh
, neigh
->holdtime
);
317 return pim_assert_recv(ifp
, neigh
, sg
.src
,
318 pim_msg
+ PIM_MSG_HEADER_LEN
,
319 pim_msg_len
- PIM_MSG_HEADER_LEN
);
321 case PIM_MSG_TYPE_BOOTSTRAP
:
322 return pim_bsm_process(ifp
, &sg
, pim_msg
, pim_msg_len
, no_fwd
);
326 if (PIM_DEBUG_PIM_PACKETS
) {
328 "Recv PIM packet type %d which is not currently understood",
335 static void pim_sock_read_on(struct interface
*ifp
);
337 static void pim_sock_read(struct event
*t
)
339 struct interface
*ifp
, *orig_ifp
;
340 struct pim_interface
*pim_ifp
;
342 struct sockaddr_storage from
;
343 struct sockaddr_storage to
;
344 socklen_t fromlen
= sizeof(from
);
345 socklen_t tolen
= sizeof(to
);
346 uint8_t buf
[PIM_PIM_BUFSIZE_READ
];
348 ifindex_t ifindex
= -1;
349 int result
= -1; /* defaults to bad */
350 static long long count
= 0;
353 orig_ifp
= ifp
= EVENT_ARG(t
);
361 len
= pim_socket_recvfromto(fd
, buf
, sizeof(buf
), &from
,
362 &fromlen
, &to
, &tolen
, &ifindex
);
366 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
369 if (PIM_DEBUG_PIM_PACKETS
)
370 zlog_debug("Received errno: %d %s", errno
,
371 safe_strerror(errno
));
376 * What? So with vrf's the incoming packet is received
377 * on the vrf interface but recvfromto above returns
378 * the right ifindex, so just use it. We know
379 * it's the right interface because we bind to it
381 ifp
= if_lookup_by_index(ifindex
, pim_ifp
->pim
->vrf
->vrf_id
);
382 if (!ifp
|| !ifp
->info
) {
383 if (PIM_DEBUG_PIM_PACKETS
)
385 "%s: Received incoming pim packet on interface(%s:%d) not yet configured for pim",
386 __func__
, ifp
? ifp
->name
: "Unknown",
391 sg
.src
= ((struct sockaddr_in
*)&from
)->sin_addr
;
392 sg
.grp
= ((struct sockaddr_in
*)&to
)->sin_addr
;
394 sg
.src
= ((struct sockaddr_in6
*)&from
)->sin6_addr
;
395 sg
.grp
= ((struct sockaddr_in6
*)&to
)->sin6_addr
;
398 int fail
= pim_pim_packet(ifp
, buf
, len
, sg
);
400 if (PIM_DEBUG_PIM_PACKETS
)
401 zlog_debug("%s: pim_pim_packet() return=%d",
407 if (count
% router
->packet_process
== 0)
411 result
= 0; /* good */
414 pim_sock_read_on(orig_ifp
);
417 ++pim_ifp
->pim_ifstat_hello_recvfail
;
421 static void pim_sock_read_on(struct interface
*ifp
)
423 struct pim_interface
*pim_ifp
;
430 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
431 zlog_debug("Scheduling READ event on PIM socket fd=%d",
432 pim_ifp
->pim_sock_fd
);
434 event_add_read(router
->master
, pim_sock_read
, ifp
, pim_ifp
->pim_sock_fd
,
435 &pim_ifp
->t_pim_sock_read
);
438 static int pim_sock_open(struct interface
*ifp
)
441 struct pim_interface
*pim_ifp
= ifp
->info
;
443 fd
= pim_socket_mcast(IPPROTO_PIM
, pim_ifp
->primary_address
, ifp
,
448 if (pim_socket_join(fd
, qpim_all_pim_routers_addr
,
449 pim_ifp
->primary_address
, ifp
->ifindex
, pim_ifp
)) {
457 void pim_ifstat_reset(struct interface
*ifp
)
459 struct pim_interface
*pim_ifp
;
468 pim_ifp
->pim_ifstat_start
= pim_time_monotonic_sec();
469 pim_ifp
->pim_ifstat_hello_sent
= 0;
470 pim_ifp
->pim_ifstat_hello_sendfail
= 0;
471 pim_ifp
->pim_ifstat_hello_recv
= 0;
472 pim_ifp
->pim_ifstat_hello_recvfail
= 0;
473 pim_ifp
->pim_ifstat_bsm_rx
= 0;
474 pim_ifp
->pim_ifstat_bsm_tx
= 0;
475 pim_ifp
->pim_ifstat_join_recv
= 0;
476 pim_ifp
->pim_ifstat_join_send
= 0;
477 pim_ifp
->pim_ifstat_prune_recv
= 0;
478 pim_ifp
->pim_ifstat_prune_send
= 0;
479 pim_ifp
->pim_ifstat_reg_recv
= 0;
480 pim_ifp
->pim_ifstat_reg_send
= 0;
481 pim_ifp
->pim_ifstat_reg_stop_recv
= 0;
482 pim_ifp
->pim_ifstat_reg_stop_send
= 0;
483 pim_ifp
->pim_ifstat_assert_recv
= 0;
484 pim_ifp
->pim_ifstat_assert_send
= 0;
485 pim_ifp
->pim_ifstat_bsm_cfg_miss
= 0;
486 pim_ifp
->pim_ifstat_ucast_bsm_cfg_miss
= 0;
487 pim_ifp
->pim_ifstat_bsm_invalid_sz
= 0;
488 pim_ifp
->igmp_ifstat_joins_sent
= 0;
489 pim_ifp
->igmp_ifstat_joins_failed
= 0;
490 pim_ifp
->igmp_peak_group_count
= 0;
493 void pim_sock_reset(struct interface
*ifp
)
495 struct pim_interface
*pim_ifp
;
502 pim_ifp
->primary_address
= pim_find_primary_addr(ifp
);
504 pim_ifp
->pim_sock_fd
= -1;
505 pim_ifp
->pim_sock_creation
= 0;
506 pim_ifp
->t_pim_sock_read
= NULL
;
508 pim_ifp
->t_pim_hello_timer
= NULL
;
509 pim_ifp
->pim_hello_period
= PIM_DEFAULT_HELLO_PERIOD
;
510 pim_ifp
->pim_default_holdtime
=
511 -1; /* unset: means 3.5 * pim_hello_period */
512 pim_ifp
->pim_triggered_hello_delay
= PIM_DEFAULT_TRIGGERED_HELLO_DELAY
;
513 pim_ifp
->pim_dr_priority
= PIM_DEFAULT_DR_PRIORITY
;
514 pim_ifp
->pim_propagation_delay_msec
=
515 PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
516 pim_ifp
->pim_override_interval_msec
=
517 PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
518 pim_ifp
->pim_can_disable_join_suppression
=
519 PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION
;
521 /* neighbors without lan_delay */
522 pim_ifp
->pim_number_of_nonlandelay_neighbors
= 0;
523 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
= 0;
524 pim_ifp
->pim_neighbors_highest_override_interval_msec
= 0;
527 pim_ifp
->pim_dr_election_last
= 0; /* timestamp */
528 pim_ifp
->pim_dr_election_count
= 0;
529 pim_ifp
->pim_dr_election_changes
= 0;
530 pim_ifp
->pim_dr_num_nondrpri_neighbors
=
531 0; /* neighbors without dr_pri */
532 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
533 pim_ifp
->am_i_dr
= true;
535 pim_ifstat_reset(ifp
);
539 static uint16_t ip_id
= 0;
543 static int pim_msg_send_frame(int fd
, char *buf
, size_t len
,
544 struct sockaddr
*dst
, size_t salen
,
547 if (sendto(fd
, buf
, len
, MSG_DONTWAIT
, dst
, salen
) >= 0)
550 if (errno
== EMSGSIZE
) {
551 struct ip
*ip
= (struct ip
*)buf
;
552 size_t hdrsize
= sizeof(struct ip
);
553 size_t newlen1
= ((len
- hdrsize
) / 2) & 0xFFF8;
554 size_t sendlen
= newlen1
+ hdrsize
;
555 size_t offset
= ntohs(ip
->ip_off
);
558 ip
->ip_len
= htons(sendlen
);
559 ip
->ip_off
= htons(offset
| IP_MF
);
561 ret
= pim_msg_send_frame(fd
, buf
, sendlen
, dst
, salen
, ifname
);
565 struct ip
*ip2
= (struct ip
*)(buf
+ newlen1
);
566 size_t newlen2
= len
- sendlen
;
568 sendlen
= newlen2
+ hdrsize
;
570 memcpy(ip2
, ip
, hdrsize
);
571 ip2
->ip_len
= htons(sendlen
);
572 ip2
->ip_off
= htons(offset
+ (newlen1
>> 3));
573 return pim_msg_send_frame(fd
, (char *)ip2
, sendlen
, dst
, salen
,
578 "%s: sendto() failure to %pSU: iface=%s fd=%d msg_size=%zd: %m",
579 __func__
, dst
, ifname
, fd
, len
);
584 static int pim_msg_send_frame(pim_addr src
, pim_addr dst
, ifindex_t ifindex
,
585 struct iovec
*message
, int fd
)
588 struct msghdr smsghdr
= {};
589 struct cmsghdr
*scmsgp
;
592 uint8_t buf
[CMSG_SPACE(sizeof(struct in6_pktinfo
))];
594 struct in6_pktinfo
*pktinfo
;
595 struct sockaddr_in6 dst_sin6
= {};
597 union cmsgbuf cmsg_buf
= {};
599 /* destination address */
600 dst_sin6
.sin6_family
= AF_INET6
;
602 dst_sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
604 dst_sin6
.sin6_addr
= dst
;
605 dst_sin6
.sin6_scope_id
= ifindex
;
608 smsghdr
.msg_iov
= message
;
609 smsghdr
.msg_iovlen
= 1;
610 smsghdr
.msg_name
= (caddr_t
)&dst_sin6
;
611 smsghdr
.msg_namelen
= sizeof(dst_sin6
);
612 smsghdr
.msg_control
= (caddr_t
)&cmsg_buf
.buf
;
613 smsghdr
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
614 smsghdr
.msg_flags
= 0;
616 scmsgp
= CMSG_FIRSTHDR(&smsghdr
);
617 scmsgp
->cmsg_level
= IPPROTO_IPV6
;
618 scmsgp
->cmsg_type
= IPV6_PKTINFO
;
619 scmsgp
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
621 pktinfo
= (struct in6_pktinfo
*)(CMSG_DATA(scmsgp
));
622 pktinfo
->ipi6_ifindex
= ifindex
;
623 pktinfo
->ipi6_addr
= src
;
625 retval
= sendmsg(fd
, &smsghdr
, 0);
629 "sendmsg failed: source: %pI6 Dest: %pI6 ifindex: %d: %s (%d)",
630 &src
, &dst
, ifindex
, safe_strerror(errno
), errno
);
636 int pim_msg_send(int fd
, pim_addr src
, pim_addr dst
, uint8_t *pim_msg
,
637 int pim_msg_size
, struct interface
*ifp
)
639 struct pim_interface
*pim_ifp
;
644 if (pim_ifp
->pim_passive_enable
) {
645 if (PIM_DEBUG_PIM_PACKETS
)
647 "skip sending PIM message on passive interface %s",
654 struct pim_msg_header
*header
;
655 unsigned char buffer
[10000];
657 memset(buffer
, 0, 10000);
659 header
= (struct pim_msg_header
*)pim_msg
;
662 * Omnios apparently doesn't have a #define for IP default
663 * ttl that is the same as all other platforms.
668 /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
669 switch (header
->type
) {
670 case PIM_MSG_TYPE_HELLO
:
671 case PIM_MSG_TYPE_JOIN_PRUNE
:
672 case PIM_MSG_TYPE_BOOTSTRAP
:
673 case PIM_MSG_TYPE_ASSERT
:
676 case PIM_MSG_TYPE_REGISTER
:
677 case PIM_MSG_TYPE_REG_STOP
:
678 case PIM_MSG_TYPE_GRAFT
:
679 case PIM_MSG_TYPE_GRAFT_ACK
:
680 case PIM_MSG_TYPE_CANDIDATE
:
688 struct ip
*ip
= (struct ip
*)buffer
;
689 struct sockaddr_in to
= {};
690 int sendlen
= sizeof(*ip
) + pim_msg_size
;
692 unsigned char *msg_start
;
694 ip
->ip_id
= htons(++ip_id
);
697 ip
->ip_tos
= IPTOS_PREC_INTERNETCONTROL
;
698 ip
->ip_p
= PIM_IP_PROTO_PIM
;
702 ip
->ip_len
= htons(sendlen
);
704 to
.sin_family
= AF_INET
;
708 msg_start
= buffer
+ sizeof(*ip
);
709 memcpy(msg_start
, pim_msg
, pim_msg_size
);
711 if (PIM_DEBUG_PIM_PACKETS
)
712 zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x",
713 __func__
, &dst
, ifp
->name
, pim_msg_size
,
716 if (PIM_DEBUG_PIM_PACKETDUMP_SEND
) {
717 pim_pkt_dump(__func__
, pim_msg
, pim_msg_size
);
720 pim_msg_send_frame(fd
, (char *)buffer
, sendlen
, (struct sockaddr
*)&to
,
725 struct iovec iovector
[2];
727 iovector
[0].iov_base
= pim_msg
;
728 iovector
[0].iov_len
= pim_msg_size
;
730 pim_msg_send_frame(src
, dst
, ifp
->ifindex
, &iovector
[0], fd
);
736 static int hello_send(struct interface
*ifp
, uint16_t holdtime
)
738 uint8_t pim_msg
[PIM_PIM_BUFSIZE_WRITE
];
739 struct pim_interface
*pim_ifp
;
745 if (PIM_DEBUG_PIM_HELLO
)
747 "%s: to %pPA on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d",
748 __func__
, &qpim_all_pim_routers_addr
, ifp
->name
,
749 holdtime
, pim_ifp
->pim_propagation_delay_msec
,
750 pim_ifp
->pim_override_interval_msec
,
751 pim_ifp
->pim_can_disable_join_suppression
,
752 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
753 listcount(ifp
->connected
));
755 pim_tlv_size
= pim_hello_build_tlv(
756 ifp
, pim_msg
+ PIM_PIM_MIN_LEN
,
757 sizeof(pim_msg
) - PIM_PIM_MIN_LEN
, holdtime
,
758 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
759 pim_ifp
->pim_propagation_delay_msec
,
760 pim_ifp
->pim_override_interval_msec
,
761 pim_ifp
->pim_can_disable_join_suppression
);
762 if (pim_tlv_size
< 0) {
766 pim_msg_size
= pim_tlv_size
+ PIM_PIM_MIN_LEN
;
768 assert(pim_msg_size
>= PIM_PIM_MIN_LEN
);
769 assert(pim_msg_size
<= PIM_PIM_BUFSIZE_WRITE
);
771 pim_msg_build_header(pim_ifp
->primary_address
,
772 qpim_all_pim_routers_addr
, pim_msg
, pim_msg_size
,
773 PIM_MSG_TYPE_HELLO
, false);
775 if (pim_msg_send(pim_ifp
->pim_sock_fd
, pim_ifp
->primary_address
,
776 qpim_all_pim_routers_addr
, pim_msg
, pim_msg_size
,
778 if (PIM_DEBUG_PIM_HELLO
) {
780 "%s: could not send PIM message on interface %s",
781 __func__
, ifp
->name
);
789 int pim_hello_send(struct interface
*ifp
, uint16_t holdtime
)
791 struct pim_interface
*pim_ifp
= ifp
->info
;
793 if (if_is_loopback(ifp
))
796 if (hello_send(ifp
, holdtime
)) {
797 ++pim_ifp
->pim_ifstat_hello_sendfail
;
799 if (PIM_DEBUG_PIM_HELLO
) {
800 zlog_warn("Could not send PIM hello on interface %s",
806 if (!pim_ifp
->pim_passive_enable
) {
807 ++pim_ifp
->pim_ifstat_hello_sent
;
808 PIM_IF_FLAG_SET_HELLO_SENT(pim_ifp
->flags
);
814 static void hello_resched(struct interface
*ifp
)
816 struct pim_interface
*pim_ifp
;
820 if (PIM_DEBUG_PIM_HELLO
) {
821 zlog_debug("Rescheduling %d sec hello on interface %s",
822 pim_ifp
->pim_hello_period
, ifp
->name
);
824 EVENT_OFF(pim_ifp
->t_pim_hello_timer
);
825 event_add_timer(router
->master
, on_pim_hello_send
, ifp
,
826 pim_ifp
->pim_hello_period
, &pim_ifp
->t_pim_hello_timer
);
832 static void on_pim_hello_send(struct event
*t
)
834 struct pim_interface
*pim_ifp
;
835 struct interface
*ifp
;
841 * Schedule next hello
848 pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
852 RFC 4601: 4.3.1. Sending Hello Messages
854 Thus, if a router needs to send a Join/Prune or Assert message on an
855 interface on which it has not yet sent a Hello message with the
856 currently configured IP address, then it MUST immediately send the
857 relevant Hello message without waiting for the Hello Timer to
858 expire, followed by the Join/Prune or Assert message.
860 void pim_hello_restart_now(struct interface
*ifp
)
862 struct pim_interface
*pim_ifp
;
867 * Reset next hello timer
872 * Immediately send hello
874 pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
878 RFC 4601: 4.3.1. Sending Hello Messages
880 To allow new or rebooting routers to learn of PIM neighbors quickly,
881 when a Hello message is received from a new neighbor, or a Hello
882 message with a new GenID is received from an existing neighbor, a
883 new Hello message should be sent on this interface after a
884 randomized delay between 0 and Triggered_Hello_Delay.
886 void pim_hello_restart_triggered(struct interface
*ifp
)
888 struct pim_interface
*pim_ifp
;
889 int triggered_hello_delay_msec
;
895 * No need to ever start loopback or vrf device hello's
897 if (if_is_loopback(ifp
))
901 * There exists situations where we have the a RPF out this
902 * interface, but we haven't formed a neighbor yet. This
903 * happens especially during interface flaps. While
904 * we would like to handle this more gracefully in other
905 * parts of the code. In order to get us up and running
906 * let's just send the hello immediate'ish
907 * This should be revisited when we get nexthop tracking
908 * in and when we have a better handle on safely
909 * handling the rpf information for upstreams that
910 * we cannot legally reach yet.
912 triggered_hello_delay_msec
= 1;
913 // triggered_hello_delay_msec = 1000 *
914 // pim_ifp->pim_triggered_hello_delay;
916 if (pim_ifp
->t_pim_hello_timer
) {
918 pim_time_timer_remain_msec(pim_ifp
->t_pim_hello_timer
);
919 if (remain_msec
<= triggered_hello_delay_msec
) {
920 /* Rescheduling hello would increase the delay, then
922 to just wait for the scheduled periodic hello. */
926 EVENT_OFF(pim_ifp
->t_pim_hello_timer
);
929 random_msec
= triggered_hello_delay_msec
;
930 // random_msec = random() % (triggered_hello_delay_msec + 1);
932 if (PIM_DEBUG_PIM_HELLO
) {
933 zlog_debug("Scheduling %d msec triggered hello on interface %s",
934 random_msec
, ifp
->name
);
937 event_add_timer_msec(router
->master
, on_pim_hello_send
, ifp
,
938 random_msec
, &pim_ifp
->t_pim_hello_timer
);
941 int pim_sock_add(struct interface
*ifp
)
943 struct pim_interface
*pim_ifp
;
949 if (pim_ifp
->pim_sock_fd
>= 0) {
950 if (PIM_DEBUG_PIM_PACKETS
)
952 "Can't recreate existing PIM socket fd=%d for interface %s",
953 pim_ifp
->pim_sock_fd
, ifp
->name
);
957 pim_ifp
->pim_sock_fd
= pim_sock_open(ifp
);
958 if (pim_ifp
->pim_sock_fd
< 0) {
959 if (PIM_DEBUG_PIM_PACKETS
)
960 zlog_debug("Could not open PIM socket on interface %s",
965 pim_socket_ip_hdr(pim_ifp
->pim_sock_fd
);
967 pim_ifp
->t_pim_sock_read
= NULL
;
968 pim_ifp
->pim_sock_creation
= pim_time_monotonic_sec();
971 * Just ensure that the new generation id
972 * actually chooses something different.
973 * Actually ran across a case where this
974 * happened, pre-switch to random().
975 * While this is unlikely to happen now
976 * let's make sure it doesn't.
978 old_genid
= pim_ifp
->pim_generation_id
;
980 while (old_genid
== pim_ifp
->pim_generation_id
)
981 pim_ifp
->pim_generation_id
= frr_weak_random();
983 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp
->name
,
987 * Start receiving PIM messages
989 pim_sock_read_on(ifp
);
992 * Start sending PIM hello's
994 pim_hello_restart_triggered(ifp
);