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
, 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",
327 static void pim_sock_read_on(struct interface
*ifp
);
329 static void pim_sock_read(struct thread
*t
)
331 struct interface
*ifp
, *orig_ifp
;
332 struct pim_interface
*pim_ifp
;
334 struct sockaddr_storage from
;
335 struct sockaddr_storage 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
->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
;
403 static void pim_sock_read_on(struct interface
*ifp
)
405 struct pim_interface
*pim_ifp
;
412 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
413 zlog_debug("Scheduling READ event on PIM socket fd=%d",
414 pim_ifp
->pim_sock_fd
);
416 thread_add_read(router
->master
, pim_sock_read
, ifp
,
417 pim_ifp
->pim_sock_fd
, &pim_ifp
->t_pim_sock_read
);
420 static int pim_sock_open(struct interface
*ifp
)
423 struct pim_interface
*pim_ifp
= ifp
->info
;
425 fd
= pim_socket_mcast(IPPROTO_PIM
, pim_ifp
->primary_address
, ifp
,
430 if (pim_socket_join(fd
, qpim_all_pim_routers_addr
,
431 pim_ifp
->primary_address
, ifp
->ifindex
, pim_ifp
)) {
439 void pim_ifstat_reset(struct interface
*ifp
)
441 struct pim_interface
*pim_ifp
;
450 pim_ifp
->pim_ifstat_start
= pim_time_monotonic_sec();
451 pim_ifp
->pim_ifstat_hello_sent
= 0;
452 pim_ifp
->pim_ifstat_hello_sendfail
= 0;
453 pim_ifp
->pim_ifstat_hello_recv
= 0;
454 pim_ifp
->pim_ifstat_hello_recvfail
= 0;
455 pim_ifp
->pim_ifstat_bsm_rx
= 0;
456 pim_ifp
->pim_ifstat_bsm_tx
= 0;
457 pim_ifp
->pim_ifstat_join_recv
= 0;
458 pim_ifp
->pim_ifstat_join_send
= 0;
459 pim_ifp
->pim_ifstat_prune_recv
= 0;
460 pim_ifp
->pim_ifstat_prune_send
= 0;
461 pim_ifp
->pim_ifstat_reg_recv
= 0;
462 pim_ifp
->pim_ifstat_reg_send
= 0;
463 pim_ifp
->pim_ifstat_reg_stop_recv
= 0;
464 pim_ifp
->pim_ifstat_reg_stop_send
= 0;
465 pim_ifp
->pim_ifstat_assert_recv
= 0;
466 pim_ifp
->pim_ifstat_assert_send
= 0;
467 pim_ifp
->pim_ifstat_bsm_cfg_miss
= 0;
468 pim_ifp
->pim_ifstat_ucast_bsm_cfg_miss
= 0;
469 pim_ifp
->pim_ifstat_bsm_invalid_sz
= 0;
470 pim_ifp
->igmp_ifstat_joins_sent
= 0;
471 pim_ifp
->igmp_ifstat_joins_failed
= 0;
474 void pim_sock_reset(struct interface
*ifp
)
476 struct pim_interface
*pim_ifp
;
483 pim_ifp
->primary_address
= pim_find_primary_addr(ifp
);
485 pim_ifp
->pim_sock_fd
= -1;
486 pim_ifp
->pim_sock_creation
= 0;
487 pim_ifp
->t_pim_sock_read
= NULL
;
489 pim_ifp
->t_pim_hello_timer
= NULL
;
490 pim_ifp
->pim_hello_period
= PIM_DEFAULT_HELLO_PERIOD
;
491 pim_ifp
->pim_default_holdtime
=
492 -1; /* unset: means 3.5 * pim_hello_period */
493 pim_ifp
->pim_triggered_hello_delay
= PIM_DEFAULT_TRIGGERED_HELLO_DELAY
;
494 pim_ifp
->pim_dr_priority
= PIM_DEFAULT_DR_PRIORITY
;
495 pim_ifp
->pim_propagation_delay_msec
=
496 PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
497 pim_ifp
->pim_override_interval_msec
=
498 PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
499 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION
) {
500 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPPRESSION(pim_ifp
->options
);
502 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPPRESSION(pim_ifp
->options
);
505 /* neighbors without lan_delay */
506 pim_ifp
->pim_number_of_nonlandelay_neighbors
= 0;
507 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
= 0;
508 pim_ifp
->pim_neighbors_highest_override_interval_msec
= 0;
511 pim_ifp
->pim_dr_election_last
= 0; /* timestamp */
512 pim_ifp
->pim_dr_election_count
= 0;
513 pim_ifp
->pim_dr_election_changes
= 0;
514 pim_ifp
->pim_dr_num_nondrpri_neighbors
=
515 0; /* neighbors without dr_pri */
516 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
517 pim_ifp
->am_i_dr
= true;
519 pim_ifstat_reset(ifp
);
522 static uint16_t ip_id
= 0;
525 static int pim_msg_send_frame(int fd
, char *buf
, size_t len
,
526 struct sockaddr
*dst
, size_t salen
)
528 struct ip
*ip
= (struct ip
*)buf
;
530 if (sendto(fd
, buf
, len
, MSG_DONTWAIT
, dst
, salen
) < 0) {
531 char dst_str
[INET_ADDRSTRLEN
];
535 size_t hdrsize
= sizeof(struct ip
);
536 size_t newlen1
= ((len
- hdrsize
) / 2) & 0xFFF8;
537 size_t sendlen
= newlen1
+ hdrsize
;
538 size_t offset
= ntohs(ip
->ip_off
);
540 ip
->ip_len
= htons(sendlen
);
541 ip
->ip_off
= htons(offset
| IP_MF
);
542 if (pim_msg_send_frame(fd
, buf
, sendlen
, dst
, salen
)
544 struct ip
*ip2
= (struct ip
*)(buf
+ newlen1
);
545 size_t newlen2
= len
- sendlen
;
546 sendlen
= newlen2
+ hdrsize
;
548 memcpy(ip2
, ip
, hdrsize
);
549 ip2
->ip_len
= htons(sendlen
);
550 ip2
->ip_off
= htons(offset
+ (newlen1
>> 3));
551 return pim_msg_send_frame(fd
, (char *)ip2
,
552 sendlen
, dst
, salen
);
558 if (PIM_DEBUG_PIM_PACKETS
) {
559 pim_inet4_dump("<dst?>", ip
->ip_dst
, dst_str
,
562 "%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
563 __func__
, dst_str
, fd
, len
, errno
,
564 safe_strerror(errno
));
573 int pim_msg_send(int fd
, pim_addr src
, pim_addr dst
, uint8_t *pim_msg
,
574 int pim_msg_size
, const char *ifname
)
576 struct sockaddr_in to
;
578 unsigned char buffer
[10000];
579 unsigned char *msg_start
;
581 struct pim_msg_header
*header
;
584 memset(buffer
, 0, 10000);
585 int sendlen
= sizeof(struct ip
) + pim_msg_size
;
587 msg_start
= buffer
+ sizeof(struct ip
);
588 memcpy(msg_start
, pim_msg
, pim_msg_size
);
590 header
= (struct pim_msg_header
*)pim_msg
;
592 * Omnios apparently doesn't have a #define for IP default
593 * ttl that is the same as all other platforms.
598 /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
599 switch (header
->type
) {
600 case PIM_MSG_TYPE_HELLO
:
601 case PIM_MSG_TYPE_JOIN_PRUNE
:
602 case PIM_MSG_TYPE_BOOTSTRAP
:
603 case PIM_MSG_TYPE_ASSERT
:
606 case PIM_MSG_TYPE_REGISTER
:
607 case PIM_MSG_TYPE_REG_STOP
:
608 case PIM_MSG_TYPE_GRAFT
:
609 case PIM_MSG_TYPE_GRAFT_ACK
:
610 case PIM_MSG_TYPE_CANDIDATE
:
618 ip
= (struct ip
*)buffer
;
619 ip
->ip_id
= htons(++ip_id
);
622 ip
->ip_tos
= IPTOS_PREC_INTERNETCONTROL
;
623 ip
->ip_p
= PIM_IP_PROTO_PIM
;
627 ip
->ip_len
= htons(sendlen
);
629 if (PIM_DEBUG_PIM_PACKETS
) {
630 char dst_str
[INET_ADDRSTRLEN
];
631 pim_inet4_dump("<dst?>", dst
, dst_str
, sizeof(dst_str
));
632 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x", __func__
,
633 dst_str
, ifname
, pim_msg_size
, header
->checksum
);
636 memset(&to
, 0, sizeof(to
));
637 to
.sin_family
= AF_INET
;
641 if (PIM_DEBUG_PIM_PACKETDUMP_SEND
) {
642 pim_pkt_dump(__func__
, pim_msg
, pim_msg_size
);
645 pim_msg_send_frame(fd
, (char *)buffer
, sendlen
, (struct sockaddr
*)&to
,
650 static int hello_send(struct interface
*ifp
, uint16_t holdtime
)
652 uint8_t pim_msg
[PIM_PIM_BUFSIZE_WRITE
];
653 struct pim_interface
*pim_ifp
;
659 if (PIM_DEBUG_PIM_HELLO
) {
660 char dst_str
[INET_ADDRSTRLEN
];
661 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr
, dst_str
,
664 "%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",
665 __func__
, dst_str
, ifp
->name
, holdtime
,
666 pim_ifp
->pim_propagation_delay_msec
,
667 pim_ifp
->pim_override_interval_msec
,
668 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPPRESSION(
670 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
671 listcount(ifp
->connected
));
674 pim_tlv_size
= pim_hello_build_tlv(
675 ifp
, pim_msg
+ PIM_PIM_MIN_LEN
,
676 sizeof(pim_msg
) - PIM_PIM_MIN_LEN
, holdtime
,
677 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
678 pim_ifp
->pim_propagation_delay_msec
,
679 pim_ifp
->pim_override_interval_msec
,
680 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPPRESSION(pim_ifp
->options
));
681 if (pim_tlv_size
< 0) {
685 pim_msg_size
= pim_tlv_size
+ PIM_PIM_MIN_LEN
;
687 assert(pim_msg_size
>= PIM_PIM_MIN_LEN
);
688 assert(pim_msg_size
<= PIM_PIM_BUFSIZE_WRITE
);
690 pim_msg_build_header(pim_msg
, pim_msg_size
, PIM_MSG_TYPE_HELLO
, false);
692 if (pim_msg_send(pim_ifp
->pim_sock_fd
, pim_ifp
->primary_address
,
693 qpim_all_pim_routers_addr
, pim_msg
, pim_msg_size
,
695 if (PIM_DEBUG_PIM_HELLO
) {
697 "%s: could not send PIM message on interface %s",
698 __func__
, ifp
->name
);
706 int pim_hello_send(struct interface
*ifp
, uint16_t holdtime
)
708 struct pim_interface
*pim_ifp
= ifp
->info
;
710 if (if_is_loopback(ifp
))
713 if (hello_send(ifp
, holdtime
)) {
714 ++pim_ifp
->pim_ifstat_hello_sendfail
;
716 if (PIM_DEBUG_PIM_HELLO
) {
717 zlog_warn("Could not send PIM hello on interface %s",
723 ++pim_ifp
->pim_ifstat_hello_sent
;
724 PIM_IF_FLAG_SET_HELLO_SENT(pim_ifp
->flags
);
729 static void hello_resched(struct interface
*ifp
)
731 struct pim_interface
*pim_ifp
;
735 if (PIM_DEBUG_PIM_HELLO
) {
736 zlog_debug("Rescheduling %d sec hello on interface %s",
737 pim_ifp
->pim_hello_period
, ifp
->name
);
739 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
740 thread_add_timer(router
->master
, on_pim_hello_send
, ifp
,
741 pim_ifp
->pim_hello_period
,
742 &pim_ifp
->t_pim_hello_timer
);
748 static void on_pim_hello_send(struct thread
*t
)
750 struct pim_interface
*pim_ifp
;
751 struct interface
*ifp
;
757 * Schedule next hello
764 pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
768 RFC 4601: 4.3.1. Sending Hello Messages
770 Thus, if a router needs to send a Join/Prune or Assert message on an
771 interface on which it has not yet sent a Hello message with the
772 currently configured IP address, then it MUST immediately send the
773 relevant Hello message without waiting for the Hello Timer to
774 expire, followed by the Join/Prune or Assert message.
776 void pim_hello_restart_now(struct interface
*ifp
)
778 struct pim_interface
*pim_ifp
;
783 * Reset next hello timer
788 * Immediately send hello
790 pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
794 RFC 4601: 4.3.1. Sending Hello Messages
796 To allow new or rebooting routers to learn of PIM neighbors quickly,
797 when a Hello message is received from a new neighbor, or a Hello
798 message with a new GenID is received from an existing neighbor, a
799 new Hello message should be sent on this interface after a
800 randomized delay between 0 and Triggered_Hello_Delay.
802 void pim_hello_restart_triggered(struct interface
*ifp
)
804 struct pim_interface
*pim_ifp
;
805 int triggered_hello_delay_msec
;
811 * No need to ever start loopback or vrf device hello's
813 if (if_is_loopback(ifp
))
817 * There exists situations where we have the a RPF out this
818 * interface, but we haven't formed a neighbor yet. This
819 * happens especially during interface flaps. While
820 * we would like to handle this more gracefully in other
821 * parts of the code. In order to get us up and running
822 * let's just send the hello immediate'ish
823 * This should be revisited when we get nexthop tracking
824 * in and when we have a better handle on safely
825 * handling the rpf information for upstreams that
826 * we cannot legally reach yet.
828 triggered_hello_delay_msec
= 1;
829 // triggered_hello_delay_msec = 1000 *
830 // pim_ifp->pim_triggered_hello_delay;
832 if (pim_ifp
->t_pim_hello_timer
) {
834 pim_time_timer_remain_msec(pim_ifp
->t_pim_hello_timer
);
835 if (remain_msec
<= triggered_hello_delay_msec
) {
836 /* Rescheduling hello would increase the delay, then
838 to just wait for the scheduled periodic hello. */
842 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
845 random_msec
= triggered_hello_delay_msec
;
846 // random_msec = random() % (triggered_hello_delay_msec + 1);
848 if (PIM_DEBUG_PIM_HELLO
) {
849 zlog_debug("Scheduling %d msec triggered hello on interface %s",
850 random_msec
, ifp
->name
);
853 thread_add_timer_msec(router
->master
, on_pim_hello_send
, ifp
,
854 random_msec
, &pim_ifp
->t_pim_hello_timer
);
857 int pim_sock_add(struct interface
*ifp
)
859 struct pim_interface
*pim_ifp
;
865 if (pim_ifp
->pim_sock_fd
>= 0) {
866 if (PIM_DEBUG_PIM_PACKETS
)
868 "Can't recreate existing PIM socket fd=%d for interface %s",
869 pim_ifp
->pim_sock_fd
, ifp
->name
);
873 pim_ifp
->pim_sock_fd
= pim_sock_open(ifp
);
874 if (pim_ifp
->pim_sock_fd
< 0) {
875 if (PIM_DEBUG_PIM_PACKETS
)
876 zlog_debug("Could not open PIM socket on interface %s",
881 pim_socket_ip_hdr(pim_ifp
->pim_sock_fd
);
883 pim_ifp
->t_pim_sock_read
= NULL
;
884 pim_ifp
->pim_sock_creation
= pim_time_monotonic_sec();
887 * Just ensure that the new generation id
888 * actually chooses something different.
889 * Actually ran across a case where this
890 * happened, pre-switch to random().
891 * While this is unlikely to happen now
892 * let's make sure it doesn't.
894 old_genid
= pim_ifp
->pim_generation_id
;
896 while (old_genid
== pim_ifp
->pim_generation_id
)
897 pim_ifp
->pim_generation_id
= frr_weak_random();
899 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp
->name
,
903 * Start receiving PIM messages
905 pim_sock_read_on(ifp
);
908 * Start sending PIM hello's
910 pim_hello_restart_triggered(ifp
);