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 int 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
, in_addr_t addr
)
143 if ((type
== PIM_MSG_TYPE_HELLO
) || (type
== PIM_MSG_TYPE_ASSERT
)
144 || (type
== PIM_MSG_TYPE_JOIN_PRUNE
)) {
145 if (addr
!= qpim_all_pim_routers_addr
.s_addr
)
152 int pim_pim_packet(struct interface
*ifp
, uint8_t *buf
, size_t len
)
155 size_t ip_hlen
; /* ip header length in bytes */
156 char src_str
[INET_ADDRSTRLEN
];
157 char dst_str
[INET_ADDRSTRLEN
];
160 uint16_t pim_checksum
; /* received checksum */
161 uint16_t checksum
; /* computed checksum */
162 struct pim_neighbor
*neigh
;
163 struct pim_msg_header
*header
;
166 if (len
< sizeof(*ip_hdr
)) {
167 if (PIM_DEBUG_PIM_PACKETS
)
169 "PIM packet size=%zu shorter than minimum=%zu",
170 len
, sizeof(*ip_hdr
));
174 ip_hdr
= (struct ip
*)buf
;
175 ip_hlen
= ip_hdr
->ip_hl
<< 2; /* ip_hl gives length in 4-byte words */
177 pim_msg
= buf
+ ip_hlen
;
178 pim_msg_len
= len
- ip_hlen
;
180 header
= (struct pim_msg_header
*)pim_msg
;
181 if (pim_msg_len
< PIM_PIM_MIN_LEN
) {
182 if (PIM_DEBUG_PIM_PACKETS
)
184 "PIM message size=%d shorter than minimum=%d",
185 pim_msg_len
, PIM_PIM_MIN_LEN
);
189 if (header
->ver
!= PIM_PROTO_VERSION
) {
190 if (PIM_DEBUG_PIM_PACKETS
)
192 "Ignoring PIM pkt from %s with unsupported version: %d",
193 ifp
->name
, header
->ver
);
197 /* save received checksum */
198 pim_checksum
= header
->checksum
;
200 /* for computing checksum */
201 header
->checksum
= 0;
202 no_fwd
= header
->Nbit
;
204 if (header
->type
== PIM_MSG_TYPE_REGISTER
) {
205 if (pim_msg_len
< PIM_MSG_REGISTER_LEN
) {
206 if (PIM_DEBUG_PIM_PACKETS
)
207 zlog_debug("PIM Register Message size=%d shorther than min length %d",
208 pim_msg_len
, PIM_MSG_REGISTER_LEN
);
211 /* First 8 byte header checksum */
212 checksum
= in_cksum(pim_msg
, PIM_MSG_REGISTER_LEN
);
213 if (checksum
!= pim_checksum
) {
214 checksum
= in_cksum(pim_msg
, pim_msg_len
);
215 if (checksum
!= pim_checksum
) {
216 if (PIM_DEBUG_PIM_PACKETS
)
218 "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
219 ifp
->name
, pim_checksum
,
226 checksum
= in_cksum(pim_msg
, pim_msg_len
);
227 if (checksum
!= pim_checksum
) {
228 if (PIM_DEBUG_PIM_PACKETS
)
230 "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
231 ifp
->name
, pim_checksum
, checksum
);
237 if (PIM_DEBUG_PIM_PACKETS
) {
238 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, src_str
,
240 pim_inet4_dump("<dst?>", ip_hdr
->ip_dst
, dst_str
,
243 "Recv PIM %s packet from %s to %s on %s: ttl=%d pim_version=%d pim_msg_size=%d checksum=%x",
244 pim_pim_msgtype2str(header
->type
), src_str
, dst_str
,
245 ifp
->name
, ip_hdr
->ip_ttl
, header
->ver
, pim_msg_len
,
247 if (PIM_DEBUG_PIM_PACKETDUMP_RECV
) {
248 pim_pkt_dump(__func__
, pim_msg
, pim_msg_len
);
252 if (!pim_pkt_dst_addr_ok(header
->type
, ip_hdr
->ip_dst
.s_addr
)) {
253 char dst_str
[INET_ADDRSTRLEN
];
254 char src_str
[INET_ADDRSTRLEN
];
256 pim_inet4_dump("<dst?>", ip_hdr
->ip_dst
, dst_str
,
258 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, src_str
,
261 "%s: Ignoring Pkt. Unexpected IP destination %s for %s (Expected: all_pim_routers_addr) from %s",
262 __func__
, dst_str
, pim_pim_msgtype2str(header
->type
),
267 switch (header
->type
) {
268 case PIM_MSG_TYPE_HELLO
:
269 return pim_hello_recv(ifp
, ip_hdr
->ip_src
,
270 pim_msg
+ PIM_MSG_HEADER_LEN
,
271 pim_msg_len
- PIM_MSG_HEADER_LEN
);
273 case PIM_MSG_TYPE_REGISTER
:
274 return pim_register_recv(ifp
, ip_hdr
->ip_dst
, ip_hdr
->ip_src
,
275 pim_msg
+ PIM_MSG_HEADER_LEN
,
276 pim_msg_len
- PIM_MSG_HEADER_LEN
);
278 case PIM_MSG_TYPE_REG_STOP
:
279 return pim_register_stop_recv(ifp
, pim_msg
+ PIM_MSG_HEADER_LEN
,
280 pim_msg_len
- PIM_MSG_HEADER_LEN
);
282 case PIM_MSG_TYPE_JOIN_PRUNE
:
283 neigh
= pim_neighbor_find(ifp
, ip_hdr
->ip_src
);
285 if (PIM_DEBUG_PIM_PACKETS
)
287 "%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
288 __FILE__
, __func__
, header
->type
,
292 pim_neighbor_timer_reset(neigh
, neigh
->holdtime
);
293 return pim_joinprune_recv(ifp
, neigh
, ip_hdr
->ip_src
,
294 pim_msg
+ PIM_MSG_HEADER_LEN
,
295 pim_msg_len
- PIM_MSG_HEADER_LEN
);
297 case PIM_MSG_TYPE_ASSERT
:
298 neigh
= pim_neighbor_find(ifp
, ip_hdr
->ip_src
);
300 if (PIM_DEBUG_PIM_PACKETS
)
302 "%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
303 __FILE__
, __func__
, header
->type
,
307 pim_neighbor_timer_reset(neigh
, neigh
->holdtime
);
308 return pim_assert_recv(ifp
, neigh
, ip_hdr
->ip_src
,
309 pim_msg
+ PIM_MSG_HEADER_LEN
,
310 pim_msg_len
- PIM_MSG_HEADER_LEN
);
312 case PIM_MSG_TYPE_BOOTSTRAP
:
313 return pim_bsm_process(ifp
, ip_hdr
, pim_msg
, pim_msg_len
,
318 if (PIM_DEBUG_PIM_PACKETS
) {
320 "Recv PIM packet type %d which is not currently understood",
328 static void pim_sock_read_on(struct interface
*ifp
);
330 static int pim_sock_read(struct thread
*t
)
332 struct interface
*ifp
, *orig_ifp
;
333 struct pim_interface
*pim_ifp
;
335 struct sockaddr_in from
;
336 struct sockaddr_in to
;
337 socklen_t fromlen
= sizeof(from
);
338 socklen_t tolen
= sizeof(to
);
339 uint8_t buf
[PIM_PIM_BUFSIZE_READ
];
341 ifindex_t ifindex
= -1;
342 int result
= -1; /* defaults to bad */
343 static long long count
= 0;
346 orig_ifp
= ifp
= THREAD_ARG(t
);
352 len
= pim_socket_recvfromto(fd
, buf
, sizeof(buf
), &from
,
353 &fromlen
, &to
, &tolen
, &ifindex
);
357 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
360 if (PIM_DEBUG_PIM_PACKETS
)
361 zlog_debug("Received errno: %d %s", errno
,
362 safe_strerror(errno
));
367 * What? So with vrf's the incoming packet is received
368 * on the vrf interface but recvfromto above returns
369 * the right ifindex, so just use it. We know
370 * it's the right interface because we bind to it
372 ifp
= if_lookup_by_index(ifindex
, pim_ifp
->pim
->vrf_id
);
373 if (!ifp
|| !ifp
->info
) {
374 if (PIM_DEBUG_PIM_PACKETS
)
376 "%s: Received incoming pim packet on interface(%s:%d) not yet configured for pim",
377 __func__
, ifp
? ifp
->name
: "Unknown",
381 int fail
= pim_pim_packet(ifp
, buf
, len
);
383 if (PIM_DEBUG_PIM_PACKETS
)
384 zlog_debug("%s: pim_pim_packet() return=%d",
390 if (count
% router
->packet_process
== 0)
394 result
= 0; /* good */
397 pim_sock_read_on(orig_ifp
);
400 ++pim_ifp
->pim_ifstat_hello_recvfail
;
406 static void pim_sock_read_on(struct interface
*ifp
)
408 struct pim_interface
*pim_ifp
;
415 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
416 zlog_debug("Scheduling READ event on PIM socket fd=%d",
417 pim_ifp
->pim_sock_fd
);
419 pim_ifp
->t_pim_sock_read
= NULL
;
420 thread_add_read(router
->master
, pim_sock_read
, ifp
,
421 pim_ifp
->pim_sock_fd
, &pim_ifp
->t_pim_sock_read
);
424 static int pim_sock_open(struct interface
*ifp
)
427 struct pim_interface
*pim_ifp
= ifp
->info
;
429 fd
= pim_socket_mcast(IPPROTO_PIM
, pim_ifp
->primary_address
, ifp
,
434 if (pim_socket_join(fd
, qpim_all_pim_routers_addr
,
435 pim_ifp
->primary_address
, ifp
->ifindex
)) {
443 void pim_ifstat_reset(struct interface
*ifp
)
445 struct pim_interface
*pim_ifp
;
454 pim_ifp
->pim_ifstat_start
= pim_time_monotonic_sec();
455 pim_ifp
->pim_ifstat_hello_sent
= 0;
456 pim_ifp
->pim_ifstat_hello_sendfail
= 0;
457 pim_ifp
->pim_ifstat_hello_recv
= 0;
458 pim_ifp
->pim_ifstat_hello_recvfail
= 0;
461 void pim_sock_reset(struct interface
*ifp
)
463 struct pim_interface
*pim_ifp
;
470 pim_ifp
->primary_address
= pim_find_primary_addr(ifp
);
472 pim_ifp
->pim_sock_fd
= -1;
473 pim_ifp
->pim_sock_creation
= 0;
474 pim_ifp
->t_pim_sock_read
= NULL
;
476 pim_ifp
->t_pim_hello_timer
= NULL
;
477 pim_ifp
->pim_hello_period
= PIM_DEFAULT_HELLO_PERIOD
;
478 pim_ifp
->pim_default_holdtime
=
479 -1; /* unset: means 3.5 * pim_hello_period */
480 pim_ifp
->pim_triggered_hello_delay
= PIM_DEFAULT_TRIGGERED_HELLO_DELAY
;
481 pim_ifp
->pim_dr_priority
= PIM_DEFAULT_DR_PRIORITY
;
482 pim_ifp
->pim_propagation_delay_msec
=
483 PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
484 pim_ifp
->pim_override_interval_msec
=
485 PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
486 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION
) {
487 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
);
489 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
);
492 /* neighbors without lan_delay */
493 pim_ifp
->pim_number_of_nonlandelay_neighbors
= 0;
494 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
= 0;
495 pim_ifp
->pim_neighbors_highest_override_interval_msec
= 0;
498 pim_ifp
->pim_dr_election_last
= 0; /* timestamp */
499 pim_ifp
->pim_dr_election_count
= 0;
500 pim_ifp
->pim_dr_election_changes
= 0;
501 pim_ifp
->pim_dr_num_nondrpri_neighbors
=
502 0; /* neighbors without dr_pri */
503 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
504 pim_ifp
->am_i_dr
= true;
506 pim_ifstat_reset(ifp
);
509 static uint16_t ip_id
= 0;
512 static int pim_msg_send_frame(int fd
, char *buf
, size_t len
,
513 struct sockaddr
*dst
, size_t salen
)
515 struct ip
*ip
= (struct ip
*)buf
;
517 while (sendto(fd
, buf
, len
, MSG_DONTWAIT
, dst
, salen
) < 0) {
518 char dst_str
[INET_ADDRSTRLEN
];
522 size_t hdrsize
= sizeof(struct ip
);
523 size_t newlen1
= ((len
- hdrsize
) / 2) & 0xFFF8;
524 size_t sendlen
= newlen1
+ hdrsize
;
525 size_t offset
= ntohs(ip
->ip_off
);
527 ip
->ip_len
= htons(sendlen
);
528 ip
->ip_off
= htons(offset
| IP_MF
);
529 if (pim_msg_send_frame(fd
, buf
, sendlen
, dst
, salen
)
531 struct ip
*ip2
= (struct ip
*)(buf
+ newlen1
);
532 size_t newlen2
= len
- sendlen
;
533 sendlen
= newlen2
+ hdrsize
;
535 memcpy(ip2
, ip
, hdrsize
);
536 ip2
->ip_len
= htons(sendlen
);
537 ip2
->ip_off
= htons(offset
+ (newlen1
>> 3));
538 return pim_msg_send_frame(fd
, (char *)ip2
,
539 sendlen
, dst
, salen
);
545 if (PIM_DEBUG_PIM_PACKETS
) {
546 pim_inet4_dump("<dst?>", ip
->ip_dst
, dst_str
,
549 "%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
550 __func__
, dst_str
, fd
, len
, errno
,
551 safe_strerror(errno
));
560 int pim_msg_send(int fd
, struct in_addr src
, struct in_addr dst
,
561 uint8_t *pim_msg
, int pim_msg_size
, const char *ifname
)
563 struct sockaddr_in to
;
565 unsigned char buffer
[10000];
566 unsigned char *msg_start
;
568 struct pim_msg_header
*header
;
571 memset(buffer
, 0, 10000);
572 int sendlen
= sizeof(struct ip
) + pim_msg_size
;
574 msg_start
= buffer
+ sizeof(struct ip
);
575 memcpy(msg_start
, pim_msg
, pim_msg_size
);
577 header
= (struct pim_msg_header
*)pim_msg
;
579 * Omnios apparently doesn't have a #define for IP default
580 * ttl that is the same as all other platforms.
585 /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
586 switch (header
->type
) {
587 case PIM_MSG_TYPE_HELLO
:
588 case PIM_MSG_TYPE_JOIN_PRUNE
:
589 case PIM_MSG_TYPE_BOOTSTRAP
:
590 case PIM_MSG_TYPE_ASSERT
:
593 case PIM_MSG_TYPE_REGISTER
:
594 case PIM_MSG_TYPE_REG_STOP
:
595 case PIM_MSG_TYPE_GRAFT
:
596 case PIM_MSG_TYPE_GRAFT_ACK
:
597 case PIM_MSG_TYPE_CANDIDATE
:
605 ip
= (struct ip
*)buffer
;
606 ip
->ip_id
= htons(++ip_id
);
609 ip
->ip_tos
= IPTOS_PREC_INTERNETCONTROL
;
610 ip
->ip_p
= PIM_IP_PROTO_PIM
;
614 ip
->ip_len
= htons(sendlen
);
616 if (PIM_DEBUG_PIM_PACKETS
) {
617 char dst_str
[INET_ADDRSTRLEN
];
618 pim_inet4_dump("<dst?>", dst
, dst_str
, sizeof(dst_str
));
619 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x", __func__
,
620 dst_str
, ifname
, pim_msg_size
, header
->checksum
);
623 memset(&to
, 0, sizeof(to
));
624 to
.sin_family
= AF_INET
;
628 if (PIM_DEBUG_PIM_PACKETDUMP_SEND
) {
629 pim_pkt_dump(__func__
, pim_msg
, pim_msg_size
);
632 pim_msg_send_frame(fd
, (char *)buffer
, sendlen
, (struct sockaddr
*)&to
,
637 static int hello_send(struct interface
*ifp
, uint16_t holdtime
)
639 uint8_t pim_msg
[PIM_PIM_BUFSIZE_WRITE
];
640 struct pim_interface
*pim_ifp
;
646 if (PIM_DEBUG_PIM_HELLO
) {
647 char dst_str
[INET_ADDRSTRLEN
];
648 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr
, dst_str
,
651 "%s: to %s on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d",
652 __func__
, dst_str
, ifp
->name
, holdtime
,
653 pim_ifp
->pim_propagation_delay_msec
,
654 pim_ifp
->pim_override_interval_msec
,
655 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(
657 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
658 listcount(ifp
->connected
));
661 pim_tlv_size
= pim_hello_build_tlv(
662 ifp
, pim_msg
+ PIM_PIM_MIN_LEN
,
663 sizeof(pim_msg
) - PIM_PIM_MIN_LEN
, holdtime
,
664 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
665 pim_ifp
->pim_propagation_delay_msec
,
666 pim_ifp
->pim_override_interval_msec
,
667 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
));
668 if (pim_tlv_size
< 0) {
672 pim_msg_size
= pim_tlv_size
+ PIM_PIM_MIN_LEN
;
674 zassert(pim_msg_size
>= PIM_PIM_MIN_LEN
);
675 zassert(pim_msg_size
<= PIM_PIM_BUFSIZE_WRITE
);
677 pim_msg_build_header(pim_msg
, pim_msg_size
, PIM_MSG_TYPE_HELLO
, false);
679 if (pim_msg_send(pim_ifp
->pim_sock_fd
, pim_ifp
->primary_address
,
680 qpim_all_pim_routers_addr
, pim_msg
, pim_msg_size
,
682 if (PIM_DEBUG_PIM_HELLO
) {
684 "%s: could not send PIM message on interface %s",
685 __func__
, ifp
->name
);
693 int pim_hello_send(struct interface
*ifp
, uint16_t holdtime
)
695 struct pim_interface
*pim_ifp
= ifp
->info
;
697 if (if_is_loopback_or_vrf(ifp
))
700 if (hello_send(ifp
, holdtime
)) {
701 ++pim_ifp
->pim_ifstat_hello_sendfail
;
703 if (PIM_DEBUG_PIM_HELLO
) {
704 zlog_warn("Could not send PIM hello on interface %s",
710 ++pim_ifp
->pim_ifstat_hello_sent
;
715 static void hello_resched(struct interface
*ifp
)
717 struct pim_interface
*pim_ifp
;
721 if (PIM_DEBUG_PIM_HELLO
) {
722 zlog_debug("Rescheduling %d sec hello on interface %s",
723 pim_ifp
->pim_hello_period
, ifp
->name
);
725 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
726 thread_add_timer(router
->master
, on_pim_hello_send
, ifp
,
727 pim_ifp
->pim_hello_period
,
728 &pim_ifp
->t_pim_hello_timer
);
734 static int on_pim_hello_send(struct thread
*t
)
736 struct pim_interface
*pim_ifp
;
737 struct interface
*ifp
;
743 * Schedule next hello
750 return pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
754 RFC 4601: 4.3.1. Sending Hello Messages
756 Thus, if a router needs to send a Join/Prune or Assert message on an
757 interface on which it has not yet sent a Hello message with the
758 currently configured IP address, then it MUST immediately send the
759 relevant Hello message without waiting for the Hello Timer to
760 expire, followed by the Join/Prune or Assert message.
762 void pim_hello_restart_now(struct interface
*ifp
)
764 struct pim_interface
*pim_ifp
;
769 * Reset next hello timer
774 * Immediately send hello
776 pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
780 RFC 4601: 4.3.1. Sending Hello Messages
782 To allow new or rebooting routers to learn of PIM neighbors quickly,
783 when a Hello message is received from a new neighbor, or a Hello
784 message with a new GenID is received from an existing neighbor, a
785 new Hello message should be sent on this interface after a
786 randomized delay between 0 and Triggered_Hello_Delay.
788 void pim_hello_restart_triggered(struct interface
*ifp
)
790 struct pim_interface
*pim_ifp
;
791 int triggered_hello_delay_msec
;
797 * No need to ever start loopback or vrf device hello's
799 if (if_is_loopback_or_vrf(ifp
))
803 * There exists situations where we have the a RPF out this
804 * interface, but we haven't formed a neighbor yet. This
805 * happens especially during interface flaps. While
806 * we would like to handle this more gracefully in other
807 * parts of the code. In order to get us up and running
808 * let's just send the hello immediate'ish
809 * This should be revisited when we get nexthop tracking
810 * in and when we have a better handle on safely
811 * handling the rpf information for upstreams that
812 * we cannot legally reach yet.
814 triggered_hello_delay_msec
= 1;
815 // triggered_hello_delay_msec = 1000 *
816 // pim_ifp->pim_triggered_hello_delay;
818 if (pim_ifp
->t_pim_hello_timer
) {
820 pim_time_timer_remain_msec(pim_ifp
->t_pim_hello_timer
);
821 if (remain_msec
<= triggered_hello_delay_msec
) {
822 /* Rescheduling hello would increase the delay, then
824 to just wait for the scheduled periodic hello. */
828 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
831 random_msec
= triggered_hello_delay_msec
;
832 // random_msec = random() % (triggered_hello_delay_msec + 1);
834 if (PIM_DEBUG_PIM_HELLO
) {
835 zlog_debug("Scheduling %d msec triggered hello on interface %s",
836 random_msec
, ifp
->name
);
839 thread_add_timer_msec(router
->master
, on_pim_hello_send
, ifp
,
840 random_msec
, &pim_ifp
->t_pim_hello_timer
);
843 int pim_sock_add(struct interface
*ifp
)
845 struct pim_interface
*pim_ifp
;
851 if (pim_ifp
->pim_sock_fd
>= 0) {
852 if (PIM_DEBUG_PIM_PACKETS
)
854 "Can't recreate existing PIM socket fd=%d for interface %s",
855 pim_ifp
->pim_sock_fd
, ifp
->name
);
859 pim_ifp
->pim_sock_fd
= pim_sock_open(ifp
);
860 if (pim_ifp
->pim_sock_fd
< 0) {
861 if (PIM_DEBUG_PIM_PACKETS
)
862 zlog_debug("Could not open PIM socket on interface %s",
867 pim_socket_ip_hdr(pim_ifp
->pim_sock_fd
);
869 pim_ifp
->t_pim_sock_read
= NULL
;
870 pim_ifp
->pim_sock_creation
= pim_time_monotonic_sec();
873 * Just ensure that the new generation id
874 * actually chooses something different.
875 * Actually ran across a case where this
876 * happened, pre-switch to random().
877 * While this is unlikely to happen now
878 * let's make sure it doesn't.
880 old_genid
= pim_ifp
->pim_generation_id
;
882 while (old_genid
== pim_ifp
->pim_generation_id
)
883 pim_ifp
->pim_generation_id
= frr_weak_random();
885 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp
->name
,
889 * Start receiving PIM messages
891 pim_sock_read_on(ifp
);
894 * Start sending PIM hello's
896 pim_hello_restart_triggered(ifp
);