3 * Copyright (C) 2008 Everton da Silva Marques
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.
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.
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
31 #include "pim_iface.h"
36 #include "pim_neighbor.h"
37 #include "pim_hello.h"
39 #include "pim_assert.h"
41 #include "pim_register.h"
42 #include "pim_errors.h"
45 static void on_pim_hello_send(struct thread
*t
);
47 static const char *pim_pim_msgtype2str(enum pim_msg_type type
)
50 case PIM_MSG_TYPE_HELLO
:
52 case PIM_MSG_TYPE_REGISTER
:
54 case PIM_MSG_TYPE_REG_STOP
:
56 case PIM_MSG_TYPE_JOIN_PRUNE
:
58 case PIM_MSG_TYPE_BOOTSTRAP
:
60 case PIM_MSG_TYPE_ASSERT
:
62 case PIM_MSG_TYPE_GRAFT
:
64 case PIM_MSG_TYPE_GRAFT_ACK
:
66 case PIM_MSG_TYPE_CANDIDATE
:
73 static void sock_close(struct interface
*ifp
)
75 struct pim_interface
*pim_ifp
= ifp
->info
;
77 if (PIM_DEBUG_PIM_TRACE
) {
78 if (pim_ifp
->t_pim_sock_read
) {
80 "Cancelling READ event for PIM socket fd=%d on interface %s",
81 pim_ifp
->pim_sock_fd
, ifp
->name
);
84 THREAD_OFF(pim_ifp
->t_pim_sock_read
);
86 if (PIM_DEBUG_PIM_TRACE
) {
87 if (pim_ifp
->t_pim_hello_timer
) {
89 "Cancelling PIM hello timer for interface %s",
93 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
95 if (PIM_DEBUG_PIM_TRACE
) {
96 zlog_debug("Deleting PIM socket fd=%d on interface %s",
97 pim_ifp
->pim_sock_fd
, ifp
->name
);
101 * If the fd is already deleted no need to do anything here
103 if (pim_ifp
->pim_sock_fd
> 0 && close(pim_ifp
->pim_sock_fd
)) {
105 "Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
106 pim_ifp
->pim_sock_fd
, ifp
->name
, errno
,
107 safe_strerror(errno
));
110 pim_ifp
->pim_sock_fd
= -1;
111 pim_ifp
->pim_sock_creation
= 0;
114 void pim_sock_delete(struct interface
*ifp
, const char *delete_message
)
116 zlog_info("PIM INTERFACE DOWN: on interface %s: %s", ifp
->name
,
120 flog_err(EC_PIM_CONFIG
,
121 "%s: %s: but PIM not enabled on interface %s (!)",
122 __func__
, delete_message
, ifp
->name
);
127 RFC 4601: 4.3.1. Sending Hello Messages
129 Before an interface goes down or changes primary IP address, a Hello
130 message with a zero HoldTime should be sent immediately (with the
131 old IP address if the IP address changed).
133 pim_hello_send(ifp
, 0 /* zero-sec holdtime */);
135 pim_neighbor_delete_all(ifp
, delete_message
);
140 /* For now check dst address for hello, assrt and join/prune is all pim rtr */
141 static bool pim_pkt_dst_addr_ok(enum pim_msg_type type
, pim_addr addr
)
143 if ((type
== PIM_MSG_TYPE_HELLO
) || (type
== PIM_MSG_TYPE_ASSERT
)
144 || (type
== PIM_MSG_TYPE_JOIN_PRUNE
)) {
145 if (pim_addr_cmp(addr
, qpim_all_pim_routers_addr
))
152 int pim_pim_packet(struct interface
*ifp
, uint8_t *buf
, size_t len
,
155 struct iovec iov
[2], *iovp
= iov
;
157 struct ip
*ip_hdr
= (struct ip
*)buf
;
158 size_t ip_hlen
; /* ip header length in bytes */
161 uint32_t pim_msg_len
= 0;
162 uint16_t pim_checksum
; /* received checksum */
163 uint16_t checksum
; /* computed checksum */
164 struct pim_neighbor
*neigh
;
165 struct pim_msg_header
*header
;
169 if (len
< sizeof(*ip_hdr
)) {
170 if (PIM_DEBUG_PIM_PACKETS
)
172 "PIM packet size=%zu shorter than minimum=%zu",
173 len
, sizeof(*ip_hdr
));
177 ip_hlen
= ip_hdr
->ip_hl
<< 2; /* ip_hl gives length in 4-byte words */
178 sg
= pim_sgaddr_from_iphdr(ip_hdr
);
180 pim_msg
= buf
+ ip_hlen
;
181 pim_msg_len
= len
- ip_hlen
;
183 struct ipv6_ph phdr
= {
187 .next_hdr
= IPPROTO_PIM
,
190 iovp
->iov_base
= &phdr
;
191 iovp
->iov_len
= sizeof(phdr
);
194 /* NB: header is not included in IPv6 RX */
199 iovp
->iov_base
= pim_msg
;
200 iovp
->iov_len
= pim_msg_len
;
203 header
= (struct pim_msg_header
*)pim_msg
;
204 if (pim_msg_len
< PIM_PIM_MIN_LEN
) {
205 if (PIM_DEBUG_PIM_PACKETS
)
207 "PIM message size=%d shorter than minimum=%d",
208 pim_msg_len
, PIM_PIM_MIN_LEN
);
212 if (header
->ver
!= PIM_PROTO_VERSION
) {
213 if (PIM_DEBUG_PIM_PACKETS
)
215 "Ignoring PIM pkt from %s with unsupported version: %d",
216 ifp
->name
, header
->ver
);
220 /* save received checksum */
221 pim_checksum
= header
->checksum
;
223 /* for computing checksum */
224 header
->checksum
= 0;
225 no_fwd
= header
->Nbit
;
227 if (header
->type
== PIM_MSG_TYPE_REGISTER
) {
228 if (pim_msg_len
< PIM_MSG_REGISTER_LEN
) {
229 if (PIM_DEBUG_PIM_PACKETS
)
230 zlog_debug("PIM Register Message size=%d shorther than min length %d",
231 pim_msg_len
, PIM_MSG_REGISTER_LEN
);
236 phdr
.ulpl
= htonl(PIM_MSG_REGISTER_LEN
);
238 /* First 8 byte header checksum */
239 iovp
[-1].iov_len
= PIM_MSG_REGISTER_LEN
;
240 checksum
= in_cksumv(iov
, iovp
- iov
);
242 if (checksum
!= pim_checksum
) {
244 phdr
.ulpl
= htonl(pim_msg_len
);
246 iovp
[-1].iov_len
= pim_msg_len
;
248 checksum
= in_cksumv(iov
, iovp
- iov
);
249 if (checksum
!= pim_checksum
) {
250 if (PIM_DEBUG_PIM_PACKETS
)
252 "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
253 ifp
->name
, pim_checksum
,
260 checksum
= in_cksumv(iov
, iovp
- iov
);
261 if (checksum
!= pim_checksum
) {
262 if (PIM_DEBUG_PIM_PACKETS
)
264 "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
265 ifp
->name
, pim_checksum
, checksum
);
271 if (PIM_DEBUG_PIM_PACKETS
) {
273 "Recv PIM %s packet from %pPA to %pPA on %s: pim_version=%d pim_msg_size=%d checksum=%x",
274 pim_pim_msgtype2str(header
->type
), &sg
.src
, &sg
.grp
,
275 ifp
->name
, header
->ver
, pim_msg_len
, checksum
);
276 if (PIM_DEBUG_PIM_PACKETDUMP_RECV
)
277 pim_pkt_dump(__func__
, pim_msg
, pim_msg_len
);
280 if (!pim_pkt_dst_addr_ok(header
->type
, sg
.grp
)) {
282 "%s: Ignoring Pkt. Unexpected IP destination %pPA for %s (Expected: all_pim_routers_addr) from %pPA",
283 __func__
, &sg
.grp
, pim_pim_msgtype2str(header
->type
),
288 switch (header
->type
) {
289 case PIM_MSG_TYPE_HELLO
:
290 return pim_hello_recv(ifp
, sg
.src
, pim_msg
+ PIM_MSG_HEADER_LEN
,
291 pim_msg_len
- PIM_MSG_HEADER_LEN
);
293 case PIM_MSG_TYPE_REGISTER
:
294 return pim_register_recv(ifp
, sg
.grp
, sg
.src
,
295 pim_msg
+ PIM_MSG_HEADER_LEN
,
296 pim_msg_len
- PIM_MSG_HEADER_LEN
);
298 case PIM_MSG_TYPE_REG_STOP
:
299 return pim_register_stop_recv(ifp
, pim_msg
+ PIM_MSG_HEADER_LEN
,
300 pim_msg_len
- PIM_MSG_HEADER_LEN
);
302 case PIM_MSG_TYPE_JOIN_PRUNE
:
303 neigh
= pim_neighbor_find(ifp
, sg
.src
);
305 if (PIM_DEBUG_PIM_PACKETS
)
307 "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
308 __FILE__
, __func__
, header
->type
,
312 pim_neighbor_timer_reset(neigh
, neigh
->holdtime
);
313 return pim_joinprune_recv(ifp
, neigh
, sg
.src
,
314 pim_msg
+ PIM_MSG_HEADER_LEN
,
315 pim_msg_len
- PIM_MSG_HEADER_LEN
);
317 case PIM_MSG_TYPE_ASSERT
:
318 neigh
= pim_neighbor_find(ifp
, sg
.src
);
320 if (PIM_DEBUG_PIM_PACKETS
)
322 "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
323 __FILE__
, __func__
, header
->type
,
327 pim_neighbor_timer_reset(neigh
, neigh
->holdtime
);
328 return pim_assert_recv(ifp
, neigh
, sg
.src
,
329 pim_msg
+ PIM_MSG_HEADER_LEN
,
330 pim_msg_len
- PIM_MSG_HEADER_LEN
);
332 case PIM_MSG_TYPE_BOOTSTRAP
:
333 return pim_bsm_process(ifp
, &sg
, pim_msg
, pim_msg_len
, no_fwd
);
337 if (PIM_DEBUG_PIM_PACKETS
) {
339 "Recv PIM packet type %d which is not currently understood",
346 static void pim_sock_read_on(struct interface
*ifp
);
348 static void pim_sock_read(struct thread
*t
)
350 struct interface
*ifp
, *orig_ifp
;
351 struct pim_interface
*pim_ifp
;
353 struct sockaddr_storage from
;
354 struct sockaddr_storage to
;
355 socklen_t fromlen
= sizeof(from
);
356 socklen_t tolen
= sizeof(to
);
357 uint8_t buf
[PIM_PIM_BUFSIZE_READ
];
359 ifindex_t ifindex
= -1;
360 int result
= -1; /* defaults to bad */
361 static long long count
= 0;
364 orig_ifp
= ifp
= THREAD_ARG(t
);
372 len
= pim_socket_recvfromto(fd
, buf
, sizeof(buf
), &from
,
373 &fromlen
, &to
, &tolen
, &ifindex
);
377 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
380 if (PIM_DEBUG_PIM_PACKETS
)
381 zlog_debug("Received errno: %d %s", errno
,
382 safe_strerror(errno
));
387 * What? So with vrf's the incoming packet is received
388 * on the vrf interface but recvfromto above returns
389 * the right ifindex, so just use it. We know
390 * it's the right interface because we bind to it
392 ifp
= if_lookup_by_index(ifindex
, pim_ifp
->pim
->vrf
->vrf_id
);
393 if (!ifp
|| !ifp
->info
) {
394 if (PIM_DEBUG_PIM_PACKETS
)
396 "%s: Received incoming pim packet on interface(%s:%d) not yet configured for pim",
397 __func__
, ifp
? ifp
->name
: "Unknown",
402 sg
.src
= ((struct sockaddr_in
*)&from
)->sin_addr
;
403 sg
.grp
= ((struct sockaddr_in
*)&to
)->sin_addr
;
405 sg
.src
= ((struct sockaddr_in6
*)&from
)->sin6_addr
;
406 sg
.grp
= ((struct sockaddr_in6
*)&to
)->sin6_addr
;
409 int fail
= pim_pim_packet(ifp
, buf
, len
, sg
);
411 if (PIM_DEBUG_PIM_PACKETS
)
412 zlog_debug("%s: pim_pim_packet() return=%d",
418 if (count
% router
->packet_process
== 0)
422 result
= 0; /* good */
425 pim_sock_read_on(orig_ifp
);
428 ++pim_ifp
->pim_ifstat_hello_recvfail
;
432 static void pim_sock_read_on(struct interface
*ifp
)
434 struct pim_interface
*pim_ifp
;
441 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
442 zlog_debug("Scheduling READ event on PIM socket fd=%d",
443 pim_ifp
->pim_sock_fd
);
445 thread_add_read(router
->master
, pim_sock_read
, ifp
,
446 pim_ifp
->pim_sock_fd
, &pim_ifp
->t_pim_sock_read
);
449 static int pim_sock_open(struct interface
*ifp
)
452 struct pim_interface
*pim_ifp
= ifp
->info
;
454 fd
= pim_socket_mcast(IPPROTO_PIM
, pim_ifp
->primary_address
, ifp
,
459 if (pim_socket_join(fd
, qpim_all_pim_routers_addr
,
460 pim_ifp
->primary_address
, ifp
->ifindex
, pim_ifp
)) {
468 void pim_ifstat_reset(struct interface
*ifp
)
470 struct pim_interface
*pim_ifp
;
479 pim_ifp
->pim_ifstat_start
= pim_time_monotonic_sec();
480 pim_ifp
->pim_ifstat_hello_sent
= 0;
481 pim_ifp
->pim_ifstat_hello_sendfail
= 0;
482 pim_ifp
->pim_ifstat_hello_recv
= 0;
483 pim_ifp
->pim_ifstat_hello_recvfail
= 0;
484 pim_ifp
->pim_ifstat_bsm_rx
= 0;
485 pim_ifp
->pim_ifstat_bsm_tx
= 0;
486 pim_ifp
->pim_ifstat_join_recv
= 0;
487 pim_ifp
->pim_ifstat_join_send
= 0;
488 pim_ifp
->pim_ifstat_prune_recv
= 0;
489 pim_ifp
->pim_ifstat_prune_send
= 0;
490 pim_ifp
->pim_ifstat_reg_recv
= 0;
491 pim_ifp
->pim_ifstat_reg_send
= 0;
492 pim_ifp
->pim_ifstat_reg_stop_recv
= 0;
493 pim_ifp
->pim_ifstat_reg_stop_send
= 0;
494 pim_ifp
->pim_ifstat_assert_recv
= 0;
495 pim_ifp
->pim_ifstat_assert_send
= 0;
496 pim_ifp
->pim_ifstat_bsm_cfg_miss
= 0;
497 pim_ifp
->pim_ifstat_ucast_bsm_cfg_miss
= 0;
498 pim_ifp
->pim_ifstat_bsm_invalid_sz
= 0;
499 pim_ifp
->igmp_ifstat_joins_sent
= 0;
500 pim_ifp
->igmp_ifstat_joins_failed
= 0;
501 pim_ifp
->igmp_peak_group_count
= 0;
504 void pim_sock_reset(struct interface
*ifp
)
506 struct pim_interface
*pim_ifp
;
513 pim_ifp
->primary_address
= pim_find_primary_addr(ifp
);
515 pim_ifp
->pim_sock_fd
= -1;
516 pim_ifp
->pim_sock_creation
= 0;
517 pim_ifp
->t_pim_sock_read
= NULL
;
519 pim_ifp
->t_pim_hello_timer
= NULL
;
520 pim_ifp
->pim_hello_period
= PIM_DEFAULT_HELLO_PERIOD
;
521 pim_ifp
->pim_default_holdtime
=
522 -1; /* unset: means 3.5 * pim_hello_period */
523 pim_ifp
->pim_triggered_hello_delay
= PIM_DEFAULT_TRIGGERED_HELLO_DELAY
;
524 pim_ifp
->pim_dr_priority
= PIM_DEFAULT_DR_PRIORITY
;
525 pim_ifp
->pim_propagation_delay_msec
=
526 PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
527 pim_ifp
->pim_override_interval_msec
=
528 PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
529 pim_ifp
->pim_can_disable_join_suppression
=
530 PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION
;
532 /* neighbors without lan_delay */
533 pim_ifp
->pim_number_of_nonlandelay_neighbors
= 0;
534 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
= 0;
535 pim_ifp
->pim_neighbors_highest_override_interval_msec
= 0;
538 pim_ifp
->pim_dr_election_last
= 0; /* timestamp */
539 pim_ifp
->pim_dr_election_count
= 0;
540 pim_ifp
->pim_dr_election_changes
= 0;
541 pim_ifp
->pim_dr_num_nondrpri_neighbors
=
542 0; /* neighbors without dr_pri */
543 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
544 pim_ifp
->am_i_dr
= true;
546 pim_ifstat_reset(ifp
);
550 static uint16_t ip_id
= 0;
553 static int pim_msg_send_frame(int fd
, char *buf
, size_t len
,
554 struct sockaddr
*dst
, size_t salen
,
557 if (sendto(fd
, buf
, len
, MSG_DONTWAIT
, dst
, salen
) >= 0)
561 if (errno
== EMSGSIZE
) {
562 struct ip
*ip
= (struct ip
*)buf
;
563 size_t hdrsize
= sizeof(struct ip
);
564 size_t newlen1
= ((len
- hdrsize
) / 2) & 0xFFF8;
565 size_t sendlen
= newlen1
+ hdrsize
;
566 size_t offset
= ntohs(ip
->ip_off
);
569 ip
->ip_len
= htons(sendlen
);
570 ip
->ip_off
= htons(offset
| IP_MF
);
572 ret
= pim_msg_send_frame(fd
, buf
, sendlen
, dst
, salen
, ifname
);
576 struct ip
*ip2
= (struct ip
*)(buf
+ newlen1
);
577 size_t newlen2
= len
- sendlen
;
579 sendlen
= newlen2
+ hdrsize
;
581 memcpy(ip2
, ip
, hdrsize
);
582 ip2
->ip_len
= htons(sendlen
);
583 ip2
->ip_off
= htons(offset
+ (newlen1
>> 3));
584 return pim_msg_send_frame(fd
, (char *)ip2
, sendlen
, dst
, salen
,
590 "%s: sendto() failure to %pSU: iface=%s fd=%d msg_size=%zd: %m",
591 __func__
, dst
, ifname
, fd
, len
);
595 int pim_msg_send(int fd
, pim_addr src
, pim_addr dst
, uint8_t *pim_msg
,
596 int pim_msg_size
, const char *ifname
)
599 unsigned char buffer
[10000];
600 unsigned char *msg_start
;
602 struct pim_msg_header
*header
;
604 memset(buffer
, 0, 10000);
606 header
= (struct pim_msg_header
*)pim_msg
;
608 * Omnios apparently doesn't have a #define for IP default
609 * ttl that is the same as all other platforms.
614 /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
615 switch (header
->type
) {
616 case PIM_MSG_TYPE_HELLO
:
617 case PIM_MSG_TYPE_JOIN_PRUNE
:
618 case PIM_MSG_TYPE_BOOTSTRAP
:
619 case PIM_MSG_TYPE_ASSERT
:
622 case PIM_MSG_TYPE_REGISTER
:
623 case PIM_MSG_TYPE_REG_STOP
:
624 case PIM_MSG_TYPE_GRAFT
:
625 case PIM_MSG_TYPE_GRAFT_ACK
:
626 case PIM_MSG_TYPE_CANDIDATE
:
635 struct ip
*ip
= (struct ip
*)buffer
;
636 struct sockaddr_in to
= {};
637 int sendlen
= sizeof(*ip
) + pim_msg_size
;
639 ip
->ip_id
= htons(++ip_id
);
642 ip
->ip_tos
= IPTOS_PREC_INTERNETCONTROL
;
643 ip
->ip_p
= PIM_IP_PROTO_PIM
;
647 ip
->ip_len
= htons(sendlen
);
649 to
.sin_family
= AF_INET
;
653 struct ip6_hdr
*ip
= (struct ip6_hdr
*)buffer
;
654 struct sockaddr_in6 to
= {};
655 int sendlen
= sizeof(*ip
) + pim_msg_size
;
658 ip
->ip6_vfc
= (6 << 4) | (IPTOS_PREC_INTERNETCONTROL
>> 4);
659 ip
->ip6_plen
= htons(pim_msg_size
);
660 ip
->ip6_nxt
= PIM_IP_PROTO_PIM
;
665 to
.sin6_family
= AF_INET6
;
670 msg_start
= buffer
+ sizeof(*ip
);
671 memcpy(msg_start
, pim_msg
, pim_msg_size
);
673 if (PIM_DEBUG_PIM_PACKETS
)
674 zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x",
675 __func__
, &dst
, ifname
, pim_msg_size
,
678 if (PIM_DEBUG_PIM_PACKETDUMP_SEND
) {
679 pim_pkt_dump(__func__
, pim_msg
, pim_msg_size
);
682 pim_msg_send_frame(fd
, (char *)buffer
, sendlen
, (struct sockaddr
*)&to
,
687 static int hello_send(struct interface
*ifp
, uint16_t holdtime
)
689 uint8_t pim_msg
[PIM_PIM_BUFSIZE_WRITE
];
690 struct pim_interface
*pim_ifp
;
696 if (PIM_DEBUG_PIM_HELLO
)
698 "%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",
699 __func__
, &qpim_all_pim_routers_addr
, ifp
->name
,
700 holdtime
, pim_ifp
->pim_propagation_delay_msec
,
701 pim_ifp
->pim_override_interval_msec
,
702 pim_ifp
->pim_can_disable_join_suppression
,
703 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
704 listcount(ifp
->connected
));
706 pim_tlv_size
= pim_hello_build_tlv(
707 ifp
, pim_msg
+ PIM_PIM_MIN_LEN
,
708 sizeof(pim_msg
) - PIM_PIM_MIN_LEN
, holdtime
,
709 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
710 pim_ifp
->pim_propagation_delay_msec
,
711 pim_ifp
->pim_override_interval_msec
,
712 pim_ifp
->pim_can_disable_join_suppression
);
713 if (pim_tlv_size
< 0) {
717 pim_msg_size
= pim_tlv_size
+ PIM_PIM_MIN_LEN
;
719 assert(pim_msg_size
>= PIM_PIM_MIN_LEN
);
720 assert(pim_msg_size
<= PIM_PIM_BUFSIZE_WRITE
);
722 pim_msg_build_header(pim_ifp
->primary_address
,
723 qpim_all_pim_routers_addr
, pim_msg
, pim_msg_size
,
724 PIM_MSG_TYPE_HELLO
, false);
726 if (pim_msg_send(pim_ifp
->pim_sock_fd
, pim_ifp
->primary_address
,
727 qpim_all_pim_routers_addr
, pim_msg
, pim_msg_size
,
729 if (PIM_DEBUG_PIM_HELLO
) {
731 "%s: could not send PIM message on interface %s",
732 __func__
, ifp
->name
);
740 int pim_hello_send(struct interface
*ifp
, uint16_t holdtime
)
742 struct pim_interface
*pim_ifp
= ifp
->info
;
744 if (if_is_loopback(ifp
))
747 if (hello_send(ifp
, holdtime
)) {
748 ++pim_ifp
->pim_ifstat_hello_sendfail
;
750 if (PIM_DEBUG_PIM_HELLO
) {
751 zlog_warn("Could not send PIM hello on interface %s",
757 ++pim_ifp
->pim_ifstat_hello_sent
;
758 PIM_IF_FLAG_SET_HELLO_SENT(pim_ifp
->flags
);
763 static void hello_resched(struct interface
*ifp
)
765 struct pim_interface
*pim_ifp
;
769 if (PIM_DEBUG_PIM_HELLO
) {
770 zlog_debug("Rescheduling %d sec hello on interface %s",
771 pim_ifp
->pim_hello_period
, ifp
->name
);
773 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
774 thread_add_timer(router
->master
, on_pim_hello_send
, ifp
,
775 pim_ifp
->pim_hello_period
,
776 &pim_ifp
->t_pim_hello_timer
);
782 static void on_pim_hello_send(struct thread
*t
)
784 struct pim_interface
*pim_ifp
;
785 struct interface
*ifp
;
791 * Schedule next hello
798 pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
802 RFC 4601: 4.3.1. Sending Hello Messages
804 Thus, if a router needs to send a Join/Prune or Assert message on an
805 interface on which it has not yet sent a Hello message with the
806 currently configured IP address, then it MUST immediately send the
807 relevant Hello message without waiting for the Hello Timer to
808 expire, followed by the Join/Prune or Assert message.
810 void pim_hello_restart_now(struct interface
*ifp
)
812 struct pim_interface
*pim_ifp
;
817 * Reset next hello timer
822 * Immediately send hello
824 pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
828 RFC 4601: 4.3.1. Sending Hello Messages
830 To allow new or rebooting routers to learn of PIM neighbors quickly,
831 when a Hello message is received from a new neighbor, or a Hello
832 message with a new GenID is received from an existing neighbor, a
833 new Hello message should be sent on this interface after a
834 randomized delay between 0 and Triggered_Hello_Delay.
836 void pim_hello_restart_triggered(struct interface
*ifp
)
838 struct pim_interface
*pim_ifp
;
839 int triggered_hello_delay_msec
;
845 * No need to ever start loopback or vrf device hello's
847 if (if_is_loopback(ifp
))
851 * There exists situations where we have the a RPF out this
852 * interface, but we haven't formed a neighbor yet. This
853 * happens especially during interface flaps. While
854 * we would like to handle this more gracefully in other
855 * parts of the code. In order to get us up and running
856 * let's just send the hello immediate'ish
857 * This should be revisited when we get nexthop tracking
858 * in and when we have a better handle on safely
859 * handling the rpf information for upstreams that
860 * we cannot legally reach yet.
862 triggered_hello_delay_msec
= 1;
863 // triggered_hello_delay_msec = 1000 *
864 // pim_ifp->pim_triggered_hello_delay;
866 if (pim_ifp
->t_pim_hello_timer
) {
868 pim_time_timer_remain_msec(pim_ifp
->t_pim_hello_timer
);
869 if (remain_msec
<= triggered_hello_delay_msec
) {
870 /* Rescheduling hello would increase the delay, then
872 to just wait for the scheduled periodic hello. */
876 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
879 random_msec
= triggered_hello_delay_msec
;
880 // random_msec = random() % (triggered_hello_delay_msec + 1);
882 if (PIM_DEBUG_PIM_HELLO
) {
883 zlog_debug("Scheduling %d msec triggered hello on interface %s",
884 random_msec
, ifp
->name
);
887 thread_add_timer_msec(router
->master
, on_pim_hello_send
, ifp
,
888 random_msec
, &pim_ifp
->t_pim_hello_timer
);
891 int pim_sock_add(struct interface
*ifp
)
893 struct pim_interface
*pim_ifp
;
899 if (pim_ifp
->pim_sock_fd
>= 0) {
900 if (PIM_DEBUG_PIM_PACKETS
)
902 "Can't recreate existing PIM socket fd=%d for interface %s",
903 pim_ifp
->pim_sock_fd
, ifp
->name
);
907 pim_ifp
->pim_sock_fd
= pim_sock_open(ifp
);
908 if (pim_ifp
->pim_sock_fd
< 0) {
909 if (PIM_DEBUG_PIM_PACKETS
)
910 zlog_debug("Could not open PIM socket on interface %s",
915 pim_socket_ip_hdr(pim_ifp
->pim_sock_fd
);
917 pim_ifp
->t_pim_sock_read
= NULL
;
918 pim_ifp
->pim_sock_creation
= pim_time_monotonic_sec();
921 * Just ensure that the new generation id
922 * actually chooses something different.
923 * Actually ran across a case where this
924 * happened, pre-switch to random().
925 * While this is unlikely to happen now
926 * let's make sure it doesn't.
928 old_genid
= pim_ifp
->pim_generation_id
;
930 while (old_genid
== pim_ifp
->pim_generation_id
)
931 pim_ifp
->pim_generation_id
= frr_weak_random();
933 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp
->name
,
937 * Start receiving PIM messages
939 pim_sock_read_on(ifp
);
942 * Start sending PIM hello's
944 pim_hello_restart_triggered(ifp
);