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
30 #include "pim_iface.h"
35 #include "pim_neighbor.h"
36 #include "pim_hello.h"
38 #include "pim_assert.h"
40 #include "pim_register.h"
41 #include "pim_errors.h"
44 static int on_pim_hello_send(struct thread
*t
);
46 static const char *pim_pim_msgtype2str(enum pim_msg_type type
)
49 case PIM_MSG_TYPE_HELLO
:
51 case PIM_MSG_TYPE_REGISTER
:
53 case PIM_MSG_TYPE_REG_STOP
:
55 case PIM_MSG_TYPE_JOIN_PRUNE
:
57 case PIM_MSG_TYPE_BOOTSTRAP
:
59 case PIM_MSG_TYPE_ASSERT
:
61 case PIM_MSG_TYPE_GRAFT
:
63 case PIM_MSG_TYPE_GRAFT_ACK
:
65 case PIM_MSG_TYPE_CANDIDATE
:
72 static void sock_close(struct interface
*ifp
)
74 struct pim_interface
*pim_ifp
= ifp
->info
;
76 if (PIM_DEBUG_PIM_TRACE
) {
77 if (pim_ifp
->t_pim_sock_read
) {
79 "Cancelling READ event for PIM socket fd=%d on interface %s",
80 pim_ifp
->pim_sock_fd
, ifp
->name
);
83 THREAD_OFF(pim_ifp
->t_pim_sock_read
);
85 if (PIM_DEBUG_PIM_TRACE
) {
86 if (pim_ifp
->t_pim_hello_timer
) {
88 "Cancelling PIM hello timer for interface %s",
92 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
94 if (PIM_DEBUG_PIM_TRACE
) {
95 zlog_debug("Deleting PIM socket fd=%d on interface %s",
96 pim_ifp
->pim_sock_fd
, ifp
->name
);
100 * If the fd is already deleted no need to do anything here
102 if (pim_ifp
->pim_sock_fd
> 0 && close(pim_ifp
->pim_sock_fd
)) {
104 "Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
105 pim_ifp
->pim_sock_fd
, ifp
->name
, errno
,
106 safe_strerror(errno
));
109 pim_ifp
->pim_sock_fd
= -1;
110 pim_ifp
->pim_sock_creation
= 0;
113 void pim_sock_delete(struct interface
*ifp
, const char *delete_message
)
115 zlog_info("PIM INTERFACE DOWN: on interface %s: %s", ifp
->name
,
119 flog_err(EC_PIM_CONFIG
,
120 "%s: %s: but PIM not enabled on interface %s (!)",
121 __func__
, delete_message
, ifp
->name
);
126 RFC 4601: 4.3.1. Sending Hello Messages
128 Before an interface goes down or changes primary IP address, a Hello
129 message with a zero HoldTime should be sent immediately (with the
130 old IP address if the IP address changed).
132 pim_hello_send(ifp
, 0 /* zero-sec holdtime */);
134 pim_neighbor_delete_all(ifp
, delete_message
);
139 /* For now check dst address for hello, assrt and join/prune is all pim rtr */
140 static bool pim_pkt_dst_addr_ok(enum pim_msg_type type
, in_addr_t addr
)
142 if ((type
== PIM_MSG_TYPE_HELLO
) || (type
== PIM_MSG_TYPE_ASSERT
)
143 || (type
== PIM_MSG_TYPE_JOIN_PRUNE
)) {
144 if (addr
!= qpim_all_pim_routers_addr
.s_addr
)
151 int pim_pim_packet(struct interface
*ifp
, uint8_t *buf
, size_t len
)
154 size_t ip_hlen
; /* ip header length in bytes */
155 char src_str
[INET_ADDRSTRLEN
];
156 char dst_str
[INET_ADDRSTRLEN
];
159 uint16_t pim_checksum
; /* received checksum */
160 uint16_t checksum
; /* computed checksum */
161 struct pim_neighbor
*neigh
;
162 struct pim_msg_header
*header
;
165 if (len
< sizeof(*ip_hdr
)) {
166 if (PIM_DEBUG_PIM_PACKETS
)
168 "PIM packet size=%zu shorter than minimum=%zu",
169 len
, sizeof(*ip_hdr
));
173 ip_hdr
= (struct ip
*)buf
;
174 ip_hlen
= ip_hdr
->ip_hl
<< 2; /* ip_hl gives length in 4-byte words */
176 pim_msg
= buf
+ ip_hlen
;
177 pim_msg_len
= len
- ip_hlen
;
179 header
= (struct pim_msg_header
*)pim_msg
;
180 if (pim_msg_len
< PIM_PIM_MIN_LEN
) {
181 if (PIM_DEBUG_PIM_PACKETS
)
183 "PIM message size=%d shorter than minimum=%d",
184 pim_msg_len
, PIM_PIM_MIN_LEN
);
188 if (header
->ver
!= PIM_PROTO_VERSION
) {
189 if (PIM_DEBUG_PIM_PACKETS
)
191 "Ignoring PIM pkt from %s with unsupported version: %d",
192 ifp
->name
, header
->ver
);
196 /* save received checksum */
197 pim_checksum
= header
->checksum
;
199 /* for computing checksum */
200 header
->checksum
= 0;
201 no_fwd
= header
->Nbit
;
203 if (header
->type
== PIM_MSG_TYPE_REGISTER
) {
204 if (pim_msg_len
< PIM_MSG_REGISTER_LEN
) {
205 if (PIM_DEBUG_PIM_PACKETS
)
206 zlog_debug("PIM Register Message size=%d shorther than min length %d",
207 pim_msg_len
, PIM_MSG_REGISTER_LEN
);
210 /* First 8 byte header checksum */
211 checksum
= in_cksum(pim_msg
, PIM_MSG_REGISTER_LEN
);
212 if (checksum
!= pim_checksum
) {
213 checksum
= in_cksum(pim_msg
, pim_msg_len
);
214 if (checksum
!= pim_checksum
) {
215 if (PIM_DEBUG_PIM_PACKETS
)
217 "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
218 ifp
->name
, pim_checksum
,
225 checksum
= in_cksum(pim_msg
, pim_msg_len
);
226 if (checksum
!= pim_checksum
) {
227 if (PIM_DEBUG_PIM_PACKETS
)
229 "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
230 ifp
->name
, pim_checksum
, checksum
);
236 if (PIM_DEBUG_PIM_PACKETS
) {
237 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, src_str
,
239 pim_inet4_dump("<dst?>", ip_hdr
->ip_dst
, dst_str
,
242 "Recv PIM %s packet from %s to %s on %s: ttl=%d pim_version=%d pim_msg_size=%d checksum=%x",
243 pim_pim_msgtype2str(header
->type
), src_str
, dst_str
,
244 ifp
->name
, ip_hdr
->ip_ttl
, header
->ver
, pim_msg_len
,
246 if (PIM_DEBUG_PIM_PACKETDUMP_RECV
) {
247 pim_pkt_dump(__func__
, pim_msg
, pim_msg_len
);
251 if (!pim_pkt_dst_addr_ok(header
->type
, ip_hdr
->ip_dst
.s_addr
)) {
252 char dst_str
[INET_ADDRSTRLEN
];
253 char src_str
[INET_ADDRSTRLEN
];
255 pim_inet4_dump("<dst?>", ip_hdr
->ip_dst
, dst_str
,
257 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, src_str
,
260 "%s: Ignoring Pkt. Unexpected IP destination %s for %s (Expected: all_pim_routers_addr) from %s",
261 __func__
, dst_str
, pim_pim_msgtype2str(header
->type
),
266 switch (header
->type
) {
267 case PIM_MSG_TYPE_HELLO
:
268 return pim_hello_recv(ifp
, ip_hdr
->ip_src
,
269 pim_msg
+ PIM_MSG_HEADER_LEN
,
270 pim_msg_len
- PIM_MSG_HEADER_LEN
);
272 case PIM_MSG_TYPE_REGISTER
:
273 return pim_register_recv(ifp
, ip_hdr
->ip_dst
, ip_hdr
->ip_src
,
274 pim_msg
+ PIM_MSG_HEADER_LEN
,
275 pim_msg_len
- PIM_MSG_HEADER_LEN
);
277 case PIM_MSG_TYPE_REG_STOP
:
278 return pim_register_stop_recv(ifp
, pim_msg
+ PIM_MSG_HEADER_LEN
,
279 pim_msg_len
- PIM_MSG_HEADER_LEN
);
281 case PIM_MSG_TYPE_JOIN_PRUNE
:
282 neigh
= pim_neighbor_find(ifp
, ip_hdr
->ip_src
);
284 if (PIM_DEBUG_PIM_PACKETS
)
286 "%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
287 __FILE__
, __func__
, header
->type
,
291 pim_neighbor_timer_reset(neigh
, neigh
->holdtime
);
292 return pim_joinprune_recv(ifp
, neigh
, ip_hdr
->ip_src
,
293 pim_msg
+ PIM_MSG_HEADER_LEN
,
294 pim_msg_len
- PIM_MSG_HEADER_LEN
);
296 case PIM_MSG_TYPE_ASSERT
:
297 neigh
= pim_neighbor_find(ifp
, ip_hdr
->ip_src
);
299 if (PIM_DEBUG_PIM_PACKETS
)
301 "%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
302 __FILE__
, __func__
, header
->type
,
306 pim_neighbor_timer_reset(neigh
, neigh
->holdtime
);
307 return pim_assert_recv(ifp
, neigh
, ip_hdr
->ip_src
,
308 pim_msg
+ PIM_MSG_HEADER_LEN
,
309 pim_msg_len
- PIM_MSG_HEADER_LEN
);
311 case PIM_MSG_TYPE_BOOTSTRAP
:
312 return pim_bsm_process(ifp
, ip_hdr
, pim_msg
, pim_msg_len
,
317 if (PIM_DEBUG_PIM_PACKETS
) {
319 "Recv PIM packet type %d which is not currently understood",
327 static void pim_sock_read_on(struct interface
*ifp
);
329 static int pim_sock_read(struct thread
*t
)
331 struct interface
*ifp
, *orig_ifp
;
332 struct pim_interface
*pim_ifp
;
334 struct sockaddr_in from
;
335 struct sockaddr_in to
;
336 socklen_t fromlen
= sizeof(from
);
337 socklen_t tolen
= sizeof(to
);
338 uint8_t buf
[PIM_PIM_BUFSIZE_READ
];
340 ifindex_t ifindex
= -1;
341 int result
= -1; /* defaults to bad */
342 static long long count
= 0;
345 orig_ifp
= ifp
= THREAD_ARG(t
);
351 len
= pim_socket_recvfromto(fd
, buf
, sizeof(buf
), &from
,
352 &fromlen
, &to
, &tolen
, &ifindex
);
356 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
359 if (PIM_DEBUG_PIM_PACKETS
)
360 zlog_debug("Received errno: %d %s", errno
,
361 safe_strerror(errno
));
366 * What? So with vrf's the incoming packet is received
367 * on the vrf interface but recvfromto above returns
368 * the right ifindex, so just use it. We know
369 * it's the right interface because we bind to it
371 ifp
= if_lookup_by_index(ifindex
, pim_ifp
->pim
->vrf_id
);
372 if (!ifp
|| !ifp
->info
) {
373 if (PIM_DEBUG_PIM_PACKETS
)
375 "%s: Received incoming pim packet on interface(%s:%d) not yet configured for pim",
376 __func__
, ifp
? ifp
->name
: "Unknown",
380 int fail
= pim_pim_packet(ifp
, buf
, len
);
382 if (PIM_DEBUG_PIM_PACKETS
)
383 zlog_debug("%s: pim_pim_packet() return=%d",
389 if (count
% router
->packet_process
== 0)
393 result
= 0; /* good */
396 pim_sock_read_on(orig_ifp
);
399 ++pim_ifp
->pim_ifstat_hello_recvfail
;
405 static void pim_sock_read_on(struct interface
*ifp
)
407 struct pim_interface
*pim_ifp
;
414 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
415 zlog_debug("Scheduling READ event on PIM socket fd=%d",
416 pim_ifp
->pim_sock_fd
);
418 pim_ifp
->t_pim_sock_read
= NULL
;
419 thread_add_read(router
->master
, pim_sock_read
, ifp
,
420 pim_ifp
->pim_sock_fd
, &pim_ifp
->t_pim_sock_read
);
423 static int pim_sock_open(struct interface
*ifp
)
426 struct pim_interface
*pim_ifp
= ifp
->info
;
428 fd
= pim_socket_mcast(IPPROTO_PIM
, pim_ifp
->primary_address
, ifp
,
433 if (pim_socket_join(fd
, qpim_all_pim_routers_addr
,
434 pim_ifp
->primary_address
, ifp
->ifindex
)) {
442 void pim_ifstat_reset(struct interface
*ifp
)
444 struct pim_interface
*pim_ifp
;
453 pim_ifp
->pim_ifstat_start
= pim_time_monotonic_sec();
454 pim_ifp
->pim_ifstat_hello_sent
= 0;
455 pim_ifp
->pim_ifstat_hello_sendfail
= 0;
456 pim_ifp
->pim_ifstat_hello_recv
= 0;
457 pim_ifp
->pim_ifstat_hello_recvfail
= 0;
460 void pim_sock_reset(struct interface
*ifp
)
462 struct pim_interface
*pim_ifp
;
469 pim_ifp
->primary_address
= pim_find_primary_addr(ifp
);
471 pim_ifp
->pim_sock_fd
= -1;
472 pim_ifp
->pim_sock_creation
= 0;
473 pim_ifp
->t_pim_sock_read
= NULL
;
475 pim_ifp
->t_pim_hello_timer
= NULL
;
476 pim_ifp
->pim_hello_period
= PIM_DEFAULT_HELLO_PERIOD
;
477 pim_ifp
->pim_default_holdtime
=
478 -1; /* unset: means 3.5 * pim_hello_period */
479 pim_ifp
->pim_triggered_hello_delay
= PIM_DEFAULT_TRIGGERED_HELLO_DELAY
;
480 pim_ifp
->pim_dr_priority
= PIM_DEFAULT_DR_PRIORITY
;
481 pim_ifp
->pim_propagation_delay_msec
=
482 PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
483 pim_ifp
->pim_override_interval_msec
=
484 PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
485 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION
) {
486 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
);
488 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
);
491 /* neighbors without lan_delay */
492 pim_ifp
->pim_number_of_nonlandelay_neighbors
= 0;
493 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
= 0;
494 pim_ifp
->pim_neighbors_highest_override_interval_msec
= 0;
497 pim_ifp
->pim_dr_election_last
= 0; /* timestamp */
498 pim_ifp
->pim_dr_election_count
= 0;
499 pim_ifp
->pim_dr_election_changes
= 0;
500 pim_ifp
->pim_dr_num_nondrpri_neighbors
=
501 0; /* neighbors without dr_pri */
502 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
504 pim_ifstat_reset(ifp
);
507 static uint16_t ip_id
= 0;
510 static int pim_msg_send_frame(int fd
, char *buf
, size_t len
,
511 struct sockaddr
*dst
, size_t salen
)
513 struct ip
*ip
= (struct ip
*)buf
;
515 while (sendto(fd
, buf
, len
, MSG_DONTWAIT
, dst
, salen
) < 0) {
516 char dst_str
[INET_ADDRSTRLEN
];
520 size_t hdrsize
= sizeof(struct ip
);
521 size_t newlen1
= ((len
- hdrsize
) / 2) & 0xFFF8;
522 size_t sendlen
= newlen1
+ hdrsize
;
523 size_t offset
= ntohs(ip
->ip_off
);
525 ip
->ip_len
= htons(sendlen
);
526 ip
->ip_off
= htons(offset
| IP_MF
);
527 if (pim_msg_send_frame(fd
, buf
, sendlen
, dst
, salen
)
529 struct ip
*ip2
= (struct ip
*)(buf
+ newlen1
);
530 size_t newlen2
= len
- sendlen
;
531 sendlen
= newlen2
+ hdrsize
;
533 memcpy(ip2
, ip
, hdrsize
);
534 ip2
->ip_len
= htons(sendlen
);
535 ip2
->ip_off
= htons(offset
+ (newlen1
>> 3));
536 return pim_msg_send_frame(fd
, (char *)ip2
,
537 sendlen
, dst
, salen
);
543 if (PIM_DEBUG_PIM_PACKETS
) {
544 pim_inet4_dump("<dst?>", ip
->ip_dst
, dst_str
,
547 "%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
548 __func__
, dst_str
, fd
, len
, errno
,
549 safe_strerror(errno
));
558 int pim_msg_send(int fd
, struct in_addr src
, struct in_addr dst
,
559 uint8_t *pim_msg
, int pim_msg_size
, const char *ifname
)
561 struct sockaddr_in to
;
563 unsigned char buffer
[10000];
564 unsigned char *msg_start
;
566 struct pim_msg_header
*header
;
569 memset(buffer
, 0, 10000);
570 int sendlen
= sizeof(struct ip
) + pim_msg_size
;
572 msg_start
= buffer
+ sizeof(struct ip
);
573 memcpy(msg_start
, pim_msg
, pim_msg_size
);
575 header
= (struct pim_msg_header
*)pim_msg
;
577 * Omnios apparently doesn't have a #define for IP default
578 * ttl that is the same as all other platforms.
583 /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
584 switch (header
->type
) {
585 case PIM_MSG_TYPE_HELLO
:
586 case PIM_MSG_TYPE_JOIN_PRUNE
:
587 case PIM_MSG_TYPE_BOOTSTRAP
:
588 case PIM_MSG_TYPE_ASSERT
:
591 case PIM_MSG_TYPE_REGISTER
:
592 case PIM_MSG_TYPE_REG_STOP
:
593 case PIM_MSG_TYPE_GRAFT
:
594 case PIM_MSG_TYPE_GRAFT_ACK
:
595 case PIM_MSG_TYPE_CANDIDATE
:
603 ip
= (struct ip
*)buffer
;
604 ip
->ip_id
= htons(++ip_id
);
607 ip
->ip_tos
= IPTOS_PREC_INTERNETCONTROL
;
608 ip
->ip_p
= PIM_IP_PROTO_PIM
;
612 ip
->ip_len
= htons(sendlen
);
614 if (PIM_DEBUG_PIM_PACKETS
) {
615 char dst_str
[INET_ADDRSTRLEN
];
616 pim_inet4_dump("<dst?>", dst
, dst_str
, sizeof(dst_str
));
617 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x", __func__
,
618 dst_str
, ifname
, pim_msg_size
, header
->checksum
);
621 memset(&to
, 0, sizeof(to
));
622 to
.sin_family
= AF_INET
;
626 if (PIM_DEBUG_PIM_PACKETDUMP_SEND
) {
627 pim_pkt_dump(__func__
, pim_msg
, pim_msg_size
);
630 pim_msg_send_frame(fd
, (char *)buffer
, sendlen
, (struct sockaddr
*)&to
,
635 static int hello_send(struct interface
*ifp
, uint16_t holdtime
)
637 uint8_t pim_msg
[PIM_PIM_BUFSIZE_WRITE
];
638 struct pim_interface
*pim_ifp
;
644 if (PIM_DEBUG_PIM_HELLO
) {
645 char dst_str
[INET_ADDRSTRLEN
];
646 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr
, dst_str
,
649 "%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",
650 __func__
, dst_str
, ifp
->name
, holdtime
,
651 pim_ifp
->pim_propagation_delay_msec
,
652 pim_ifp
->pim_override_interval_msec
,
653 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(
655 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
656 listcount(ifp
->connected
));
659 pim_tlv_size
= pim_hello_build_tlv(
660 ifp
, pim_msg
+ PIM_PIM_MIN_LEN
,
661 sizeof(pim_msg
) - PIM_PIM_MIN_LEN
, holdtime
,
662 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
663 pim_ifp
->pim_propagation_delay_msec
,
664 pim_ifp
->pim_override_interval_msec
,
665 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
));
666 if (pim_tlv_size
< 0) {
670 pim_msg_size
= pim_tlv_size
+ PIM_PIM_MIN_LEN
;
672 zassert(pim_msg_size
>= PIM_PIM_MIN_LEN
);
673 zassert(pim_msg_size
<= PIM_PIM_BUFSIZE_WRITE
);
675 pim_msg_build_header(pim_msg
, pim_msg_size
, PIM_MSG_TYPE_HELLO
, false);
677 if (pim_msg_send(pim_ifp
->pim_sock_fd
, pim_ifp
->primary_address
,
678 qpim_all_pim_routers_addr
, pim_msg
, pim_msg_size
,
680 if (PIM_DEBUG_PIM_HELLO
) {
682 "%s: could not send PIM message on interface %s",
683 __func__
, ifp
->name
);
691 int pim_hello_send(struct interface
*ifp
, uint16_t holdtime
)
693 struct pim_interface
*pim_ifp
= ifp
->info
;
695 if (if_is_loopback_or_vrf(ifp
))
698 if (hello_send(ifp
, holdtime
)) {
699 ++pim_ifp
->pim_ifstat_hello_sendfail
;
701 if (PIM_DEBUG_PIM_HELLO
) {
702 zlog_warn("Could not send PIM hello on interface %s",
708 ++pim_ifp
->pim_ifstat_hello_sent
;
713 static void hello_resched(struct interface
*ifp
)
715 struct pim_interface
*pim_ifp
;
719 if (PIM_DEBUG_PIM_HELLO
) {
720 zlog_debug("Rescheduling %d sec hello on interface %s",
721 pim_ifp
->pim_hello_period
, ifp
->name
);
723 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
724 thread_add_timer(router
->master
, on_pim_hello_send
, ifp
,
725 pim_ifp
->pim_hello_period
,
726 &pim_ifp
->t_pim_hello_timer
);
732 static int on_pim_hello_send(struct thread
*t
)
734 struct pim_interface
*pim_ifp
;
735 struct interface
*ifp
;
741 * Schedule next hello
748 return pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
752 RFC 4601: 4.3.1. Sending Hello Messages
754 Thus, if a router needs to send a Join/Prune or Assert message on an
755 interface on which it has not yet sent a Hello message with the
756 currently configured IP address, then it MUST immediately send the
757 relevant Hello message without waiting for the Hello Timer to
758 expire, followed by the Join/Prune or Assert message.
760 void pim_hello_restart_now(struct interface
*ifp
)
762 struct pim_interface
*pim_ifp
;
767 * Reset next hello timer
772 * Immediately send hello
774 pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
778 RFC 4601: 4.3.1. Sending Hello Messages
780 To allow new or rebooting routers to learn of PIM neighbors quickly,
781 when a Hello message is received from a new neighbor, or a Hello
782 message with a new GenID is received from an existing neighbor, a
783 new Hello message should be sent on this interface after a
784 randomized delay between 0 and Triggered_Hello_Delay.
786 void pim_hello_restart_triggered(struct interface
*ifp
)
788 struct pim_interface
*pim_ifp
;
789 int triggered_hello_delay_msec
;
795 * No need to ever start loopback or vrf device hello's
797 if (if_is_loopback_or_vrf(ifp
))
801 * There exists situations where we have the a RPF out this
802 * interface, but we haven't formed a neighbor yet. This
803 * happens especially during interface flaps. While
804 * we would like to handle this more gracefully in other
805 * parts of the code. In order to get us up and running
806 * let's just send the hello immediate'ish
807 * This should be revisited when we get nexthop tracking
808 * in and when we have a better handle on safely
809 * handling the rpf information for upstreams that
810 * we cannot legally reach yet.
812 triggered_hello_delay_msec
= 1;
813 // triggered_hello_delay_msec = 1000 *
814 // pim_ifp->pim_triggered_hello_delay;
816 if (pim_ifp
->t_pim_hello_timer
) {
818 pim_time_timer_remain_msec(pim_ifp
->t_pim_hello_timer
);
819 if (remain_msec
<= triggered_hello_delay_msec
) {
820 /* Rescheduling hello would increase the delay, then
822 to just wait for the scheduled periodic hello. */
826 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
829 random_msec
= triggered_hello_delay_msec
;
830 // random_msec = random() % (triggered_hello_delay_msec + 1);
832 if (PIM_DEBUG_PIM_HELLO
) {
833 zlog_debug("Scheduling %d msec triggered hello on interface %s",
834 random_msec
, ifp
->name
);
837 thread_add_timer_msec(router
->master
, on_pim_hello_send
, ifp
,
838 random_msec
, &pim_ifp
->t_pim_hello_timer
);
841 int pim_sock_add(struct interface
*ifp
)
843 struct pim_interface
*pim_ifp
;
849 if (pim_ifp
->pim_sock_fd
>= 0) {
850 if (PIM_DEBUG_PIM_PACKETS
)
852 "Can't recreate existing PIM socket fd=%d for interface %s",
853 pim_ifp
->pim_sock_fd
, ifp
->name
);
857 pim_ifp
->pim_sock_fd
= pim_sock_open(ifp
);
858 if (pim_ifp
->pim_sock_fd
< 0) {
859 if (PIM_DEBUG_PIM_PACKETS
)
860 zlog_debug("Could not open PIM socket on interface %s",
865 pim_socket_ip_hdr(pim_ifp
->pim_sock_fd
);
867 pim_ifp
->t_pim_sock_read
= NULL
;
868 pim_ifp
->pim_sock_creation
= pim_time_monotonic_sec();
871 * Just ensure that the new generation id
872 * actually chooses something different.
873 * Actually ran across a case where this
874 * happened, pre-switch to random().
875 * While this is unlikely to happen now
876 * let's make sure it doesn't.
878 old_genid
= pim_ifp
->pim_generation_id
;
880 while (old_genid
== pim_ifp
->pim_generation_id
)
881 pim_ifp
->pim_generation_id
= random();
883 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp
->name
,
887 * Start receiving PIM messages
889 pim_sock_read_on(ifp
);
892 * Start sending PIM hello's
894 pim_hello_restart_triggered(ifp
);