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
;
505 pim_ifstat_reset(ifp
);
508 static uint16_t ip_id
= 0;
511 static int pim_msg_send_frame(int fd
, char *buf
, size_t len
,
512 struct sockaddr
*dst
, size_t salen
)
514 struct ip
*ip
= (struct ip
*)buf
;
516 while (sendto(fd
, buf
, len
, MSG_DONTWAIT
, dst
, salen
) < 0) {
517 char dst_str
[INET_ADDRSTRLEN
];
521 size_t hdrsize
= sizeof(struct ip
);
522 size_t newlen1
= ((len
- hdrsize
) / 2) & 0xFFF8;
523 size_t sendlen
= newlen1
+ hdrsize
;
524 size_t offset
= ntohs(ip
->ip_off
);
526 ip
->ip_len
= htons(sendlen
);
527 ip
->ip_off
= htons(offset
| IP_MF
);
528 if (pim_msg_send_frame(fd
, buf
, sendlen
, dst
, salen
)
530 struct ip
*ip2
= (struct ip
*)(buf
+ newlen1
);
531 size_t newlen2
= len
- sendlen
;
532 sendlen
= newlen2
+ hdrsize
;
534 memcpy(ip2
, ip
, hdrsize
);
535 ip2
->ip_len
= htons(sendlen
);
536 ip2
->ip_off
= htons(offset
+ (newlen1
>> 3));
537 return pim_msg_send_frame(fd
, (char *)ip2
,
538 sendlen
, dst
, salen
);
544 if (PIM_DEBUG_PIM_PACKETS
) {
545 pim_inet4_dump("<dst?>", ip
->ip_dst
, dst_str
,
548 "%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
549 __func__
, dst_str
, fd
, len
, errno
,
550 safe_strerror(errno
));
559 int pim_msg_send(int fd
, struct in_addr src
, struct in_addr dst
,
560 uint8_t *pim_msg
, int pim_msg_size
, const char *ifname
)
562 struct sockaddr_in to
;
564 unsigned char buffer
[10000];
565 unsigned char *msg_start
;
567 struct pim_msg_header
*header
;
570 memset(buffer
, 0, 10000);
571 int sendlen
= sizeof(struct ip
) + pim_msg_size
;
573 msg_start
= buffer
+ sizeof(struct ip
);
574 memcpy(msg_start
, pim_msg
, pim_msg_size
);
576 header
= (struct pim_msg_header
*)pim_msg
;
578 * Omnios apparently doesn't have a #define for IP default
579 * ttl that is the same as all other platforms.
584 /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
585 switch (header
->type
) {
586 case PIM_MSG_TYPE_HELLO
:
587 case PIM_MSG_TYPE_JOIN_PRUNE
:
588 case PIM_MSG_TYPE_BOOTSTRAP
:
589 case PIM_MSG_TYPE_ASSERT
:
592 case PIM_MSG_TYPE_REGISTER
:
593 case PIM_MSG_TYPE_REG_STOP
:
594 case PIM_MSG_TYPE_GRAFT
:
595 case PIM_MSG_TYPE_GRAFT_ACK
:
596 case PIM_MSG_TYPE_CANDIDATE
:
604 ip
= (struct ip
*)buffer
;
605 ip
->ip_id
= htons(++ip_id
);
608 ip
->ip_tos
= IPTOS_PREC_INTERNETCONTROL
;
609 ip
->ip_p
= PIM_IP_PROTO_PIM
;
613 ip
->ip_len
= htons(sendlen
);
615 if (PIM_DEBUG_PIM_PACKETS
) {
616 char dst_str
[INET_ADDRSTRLEN
];
617 pim_inet4_dump("<dst?>", dst
, dst_str
, sizeof(dst_str
));
618 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x", __func__
,
619 dst_str
, ifname
, pim_msg_size
, header
->checksum
);
622 memset(&to
, 0, sizeof(to
));
623 to
.sin_family
= AF_INET
;
627 if (PIM_DEBUG_PIM_PACKETDUMP_SEND
) {
628 pim_pkt_dump(__func__
, pim_msg
, pim_msg_size
);
631 pim_msg_send_frame(fd
, (char *)buffer
, sendlen
, (struct sockaddr
*)&to
,
636 static int hello_send(struct interface
*ifp
, uint16_t holdtime
)
638 uint8_t pim_msg
[PIM_PIM_BUFSIZE_WRITE
];
639 struct pim_interface
*pim_ifp
;
645 if (PIM_DEBUG_PIM_HELLO
) {
646 char dst_str
[INET_ADDRSTRLEN
];
647 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr
, dst_str
,
650 "%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",
651 __func__
, dst_str
, ifp
->name
, holdtime
,
652 pim_ifp
->pim_propagation_delay_msec
,
653 pim_ifp
->pim_override_interval_msec
,
654 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(
656 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
657 listcount(ifp
->connected
));
660 pim_tlv_size
= pim_hello_build_tlv(
661 ifp
, pim_msg
+ PIM_PIM_MIN_LEN
,
662 sizeof(pim_msg
) - PIM_PIM_MIN_LEN
, holdtime
,
663 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
664 pim_ifp
->pim_propagation_delay_msec
,
665 pim_ifp
->pim_override_interval_msec
,
666 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
));
667 if (pim_tlv_size
< 0) {
671 pim_msg_size
= pim_tlv_size
+ PIM_PIM_MIN_LEN
;
673 zassert(pim_msg_size
>= PIM_PIM_MIN_LEN
);
674 zassert(pim_msg_size
<= PIM_PIM_BUFSIZE_WRITE
);
676 pim_msg_build_header(pim_msg
, pim_msg_size
, PIM_MSG_TYPE_HELLO
, false);
678 if (pim_msg_send(pim_ifp
->pim_sock_fd
, pim_ifp
->primary_address
,
679 qpim_all_pim_routers_addr
, pim_msg
, pim_msg_size
,
681 if (PIM_DEBUG_PIM_HELLO
) {
683 "%s: could not send PIM message on interface %s",
684 __func__
, ifp
->name
);
692 int pim_hello_send(struct interface
*ifp
, uint16_t holdtime
)
694 struct pim_interface
*pim_ifp
= ifp
->info
;
696 if (if_is_loopback_or_vrf(ifp
))
699 if (hello_send(ifp
, holdtime
)) {
700 ++pim_ifp
->pim_ifstat_hello_sendfail
;
702 if (PIM_DEBUG_PIM_HELLO
) {
703 zlog_warn("Could not send PIM hello on interface %s",
709 ++pim_ifp
->pim_ifstat_hello_sent
;
714 static void hello_resched(struct interface
*ifp
)
716 struct pim_interface
*pim_ifp
;
720 if (PIM_DEBUG_PIM_HELLO
) {
721 zlog_debug("Rescheduling %d sec hello on interface %s",
722 pim_ifp
->pim_hello_period
, ifp
->name
);
724 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
725 thread_add_timer(router
->master
, on_pim_hello_send
, ifp
,
726 pim_ifp
->pim_hello_period
,
727 &pim_ifp
->t_pim_hello_timer
);
733 static int on_pim_hello_send(struct thread
*t
)
735 struct pim_interface
*pim_ifp
;
736 struct interface
*ifp
;
742 * Schedule next hello
749 return pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
753 RFC 4601: 4.3.1. Sending Hello Messages
755 Thus, if a router needs to send a Join/Prune or Assert message on an
756 interface on which it has not yet sent a Hello message with the
757 currently configured IP address, then it MUST immediately send the
758 relevant Hello message without waiting for the Hello Timer to
759 expire, followed by the Join/Prune or Assert message.
761 void pim_hello_restart_now(struct interface
*ifp
)
763 struct pim_interface
*pim_ifp
;
768 * Reset next hello timer
773 * Immediately send hello
775 pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
779 RFC 4601: 4.3.1. Sending Hello Messages
781 To allow new or rebooting routers to learn of PIM neighbors quickly,
782 when a Hello message is received from a new neighbor, or a Hello
783 message with a new GenID is received from an existing neighbor, a
784 new Hello message should be sent on this interface after a
785 randomized delay between 0 and Triggered_Hello_Delay.
787 void pim_hello_restart_triggered(struct interface
*ifp
)
789 struct pim_interface
*pim_ifp
;
790 int triggered_hello_delay_msec
;
796 * No need to ever start loopback or vrf device hello's
798 if (if_is_loopback_or_vrf(ifp
))
802 * There exists situations where we have the a RPF out this
803 * interface, but we haven't formed a neighbor yet. This
804 * happens especially during interface flaps. While
805 * we would like to handle this more gracefully in other
806 * parts of the code. In order to get us up and running
807 * let's just send the hello immediate'ish
808 * This should be revisited when we get nexthop tracking
809 * in and when we have a better handle on safely
810 * handling the rpf information for upstreams that
811 * we cannot legally reach yet.
813 triggered_hello_delay_msec
= 1;
814 // triggered_hello_delay_msec = 1000 *
815 // pim_ifp->pim_triggered_hello_delay;
817 if (pim_ifp
->t_pim_hello_timer
) {
819 pim_time_timer_remain_msec(pim_ifp
->t_pim_hello_timer
);
820 if (remain_msec
<= triggered_hello_delay_msec
) {
821 /* Rescheduling hello would increase the delay, then
823 to just wait for the scheduled periodic hello. */
827 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
830 random_msec
= triggered_hello_delay_msec
;
831 // random_msec = random() % (triggered_hello_delay_msec + 1);
833 if (PIM_DEBUG_PIM_HELLO
) {
834 zlog_debug("Scheduling %d msec triggered hello on interface %s",
835 random_msec
, ifp
->name
);
838 thread_add_timer_msec(router
->master
, on_pim_hello_send
, ifp
,
839 random_msec
, &pim_ifp
->t_pim_hello_timer
);
842 int pim_sock_add(struct interface
*ifp
)
844 struct pim_interface
*pim_ifp
;
850 if (pim_ifp
->pim_sock_fd
>= 0) {
851 if (PIM_DEBUG_PIM_PACKETS
)
853 "Can't recreate existing PIM socket fd=%d for interface %s",
854 pim_ifp
->pim_sock_fd
, ifp
->name
);
858 pim_ifp
->pim_sock_fd
= pim_sock_open(ifp
);
859 if (pim_ifp
->pim_sock_fd
< 0) {
860 if (PIM_DEBUG_PIM_PACKETS
)
861 zlog_debug("Could not open PIM socket on interface %s",
866 pim_socket_ip_hdr(pim_ifp
->pim_sock_fd
);
868 pim_ifp
->t_pim_sock_read
= NULL
;
869 pim_ifp
->pim_sock_creation
= pim_time_monotonic_sec();
872 * Just ensure that the new generation id
873 * actually chooses something different.
874 * Actually ran across a case where this
875 * happened, pre-switch to random().
876 * While this is unlikely to happen now
877 * let's make sure it doesn't.
879 old_genid
= pim_ifp
->pim_generation_id
;
881 while (old_genid
== pim_ifp
->pim_generation_id
)
882 pim_ifp
->pim_generation_id
= frr_weak_random();
884 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp
->name
,
888 * Start receiving PIM messages
890 pim_sock_read_on(ifp
);
893 * Start sending PIM hello's
895 pim_hello_restart_triggered(ifp
);