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
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
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"
43 static int on_pim_hello_send(struct thread
*t
);
44 static int pim_hello_send(struct interface
*ifp
,
47 static void sock_close(struct interface
*ifp
)
49 struct pim_interface
*pim_ifp
= ifp
->info
;
51 if (PIM_DEBUG_PIM_TRACE
) {
52 if (pim_ifp
->t_pim_sock_read
) {
53 zlog_debug("Cancelling READ event for PIM socket fd=%d on interface %s",
58 THREAD_OFF(pim_ifp
->t_pim_sock_read
);
60 if (PIM_DEBUG_PIM_TRACE
) {
61 if (pim_ifp
->t_pim_hello_timer
) {
62 zlog_debug("Cancelling PIM hello timer for interface %s",
66 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
68 if (PIM_DEBUG_PIM_TRACE
) {
69 zlog_debug("Deleting PIM socket fd=%d on interface %s",
70 pim_ifp
->pim_sock_fd
, ifp
->name
);
73 if (close(pim_ifp
->pim_sock_fd
)) {
74 zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
75 pim_ifp
->pim_sock_fd
, ifp
->name
,
76 errno
, safe_strerror(errno
));
79 pim_ifp
->pim_sock_fd
= -1;
80 pim_ifp
->pim_sock_creation
= 0;
82 zassert(pim_ifp
->pim_sock_fd
< 0);
83 zassert(!pim_ifp
->t_pim_sock_read
);
84 zassert(!pim_ifp
->t_pim_hello_timer
);
85 zassert(!pim_ifp
->pim_sock_creation
);
88 void pim_sock_delete(struct interface
*ifp
, const char *delete_message
)
90 zlog_info("PIM INTERFACE DOWN: on interface %s: %s",
91 ifp
->name
, delete_message
);
94 zlog_err("%s: %s: but PIM not enabled on interface %s (!)",
95 __PRETTY_FUNCTION__
, delete_message
, ifp
->name
);
100 RFC 4601: 4.3.1. Sending Hello Messages
102 Before an interface goes down or changes primary IP address, a Hello
103 message with a zero HoldTime should be sent immediately (with the
104 old IP address if the IP address changed).
106 pim_hello_send(ifp
, 0 /* zero-sec holdtime */);
108 pim_neighbor_delete_all(ifp
, delete_message
);
113 int pim_pim_packet(struct interface
*ifp
, uint8_t *buf
, size_t len
)
116 size_t ip_hlen
; /* ip header length in bytes */
123 uint16_t pim_checksum
; /* received checksum */
124 uint16_t checksum
; /* computed checksum */
125 struct pim_neighbor
*neigh
;
128 zlog_warn("%s: PIM not enabled on interface %s",
129 __PRETTY_FUNCTION__
, ifp
->name
);
133 if (len
< sizeof(*ip_hdr
)) {
134 zlog_warn("PIM packet size=%zu shorter than minimum=%zu",
135 len
, sizeof(*ip_hdr
));
139 ip_hdr
= (struct ip
*) buf
;
141 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, src_str
, sizeof(src_str
));
142 pim_inet4_dump("<dst?>", ip_hdr
->ip_dst
, dst_str
, sizeof(dst_str
));
144 ip_hlen
= ip_hdr
->ip_hl
<< 2; /* ip_hl gives length in 4-byte words */
146 if (PIM_DEBUG_PIM_PACKETS
) {
147 zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d",
148 src_str
, dst_str
, ifp
->name
, len
, ip_hlen
, ip_hdr
->ip_p
);
151 if (ip_hdr
->ip_p
!= PIM_IP_PROTO_PIM
) {
152 zlog_warn("IP packet protocol=%d is not PIM=%d",
153 ip_hdr
->ip_p
, PIM_IP_PROTO_PIM
);
157 if (ip_hlen
< PIM_IP_HEADER_MIN_LEN
) {
158 zlog_warn("IP packet header size=%zu shorter than minimum=%d",
159 ip_hlen
, PIM_IP_HEADER_MIN_LEN
);
162 if (ip_hlen
> PIM_IP_HEADER_MAX_LEN
) {
163 zlog_warn("IP packet header size=%zu greater than maximum=%d",
164 ip_hlen
, PIM_IP_HEADER_MAX_LEN
);
168 pim_msg
= buf
+ ip_hlen
;
169 pim_msg_len
= len
- ip_hlen
;
171 if (PIM_DEBUG_PIM_PACKETDUMP_RECV
) {
172 pim_pkt_dump(__PRETTY_FUNCTION__
, pim_msg
, pim_msg_len
);
175 if (pim_msg_len
< PIM_PIM_MIN_LEN
) {
176 zlog_warn("PIM message size=%d shorter than minimum=%d",
177 pim_msg_len
, PIM_PIM_MIN_LEN
);
181 pim_version
= PIM_MSG_HDR_GET_VERSION(pim_msg
);
182 pim_type
= PIM_MSG_HDR_GET_TYPE(pim_msg
);
184 if (pim_version
!= PIM_PROTO_VERSION
) {
185 zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d",
186 ifp
->name
, pim_version
);
190 /* save received checksum */
191 pim_checksum
= PIM_MSG_HDR_GET_CHECKSUM(pim_msg
);
193 /* for computing checksum */
194 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg
) = 0;
196 checksum
= in_cksum(pim_msg
, pim_msg_len
);
197 if (checksum
!= pim_checksum
) {
198 zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
199 ifp
->name
, pim_checksum
, checksum
);
203 if (PIM_DEBUG_PIM_PACKETS
) {
204 zlog_debug("Recv PIM packet from %s to %s on %s: ttl=%d pim_version=%d pim_type=%d pim_msg_size=%d checksum=%x",
205 src_str
, dst_str
, ifp
->name
, ip_hdr
->ip_ttl
,
206 pim_version
, pim_type
, pim_msg_len
, checksum
);
209 if (pim_type
== PIM_MSG_TYPE_REG_STOP
||
210 pim_type
== PIM_MSG_TYPE_BOOTSTRAP
||
211 pim_type
== PIM_MSG_TYPE_GRAFT
||
212 pim_type
== PIM_MSG_TYPE_GRAFT_ACK
||
213 pim_type
== PIM_MSG_TYPE_CANDIDATE
)
215 if (PIM_DEBUG_PIM_PACKETS
) {
216 zlog_debug("Recv PIM packet type %d which is not currently understood",
222 if (pim_type
== PIM_MSG_TYPE_HELLO
) {
223 return pim_hello_recv(ifp
,
225 pim_msg
+ PIM_MSG_HEADER_LEN
,
226 pim_msg_len
- PIM_MSG_HEADER_LEN
);
227 } else if (pim_type
== PIM_MSG_TYPE_REGISTER
) {
228 return pim_register_recv(ifp
,
231 pim_msg
+ PIM_MSG_HEADER_LEN
,
232 pim_msg_len
- PIM_MSG_HEADER_LEN
);
235 neigh
= pim_neighbor_find(ifp
, ip_hdr
->ip_src
);
237 zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
238 __FILE__
, __PRETTY_FUNCTION__
,
239 pim_type
, src_str
, ifp
->name
);
244 case PIM_MSG_TYPE_JOIN_PRUNE
:
245 return pim_joinprune_recv(ifp
, neigh
,
247 pim_msg
+ PIM_MSG_HEADER_LEN
,
248 pim_msg_len
- PIM_MSG_HEADER_LEN
);
250 case PIM_MSG_TYPE_ASSERT
:
251 return pim_assert_recv(ifp
, neigh
,
253 pim_msg
+ PIM_MSG_HEADER_LEN
,
254 pim_msg_len
- PIM_MSG_HEADER_LEN
);
257 zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s",
258 __FILE__
, __PRETTY_FUNCTION__
,
259 pim_type
, src_str
, ifp
->name
);
266 static void pim_sock_read_on(struct interface
*ifp
);
268 static int pim_sock_read(struct thread
*t
)
270 struct interface
*ifp
;
271 struct pim_interface
*pim_ifp
;
273 struct sockaddr_in from
;
274 struct sockaddr_in to
;
275 socklen_t fromlen
= sizeof(from
);
276 socklen_t tolen
= sizeof(to
);
277 uint8_t buf
[PIM_PIM_BUFSIZE_READ
];
279 ifindex_t ifindex
= -1;
280 int result
= -1; /* defaults to bad */
292 zassert(fd
== pim_ifp
->pim_sock_fd
);
294 len
= pim_socket_recvfromto(fd
, buf
, sizeof(buf
),
299 zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s",
300 fd
, errno
, safe_strerror(errno
));
304 if (PIM_DEBUG_PIM_PACKETS
) {
308 if (!inet_ntop(AF_INET
, &from
.sin_addr
, from_str
, sizeof(from_str
)))
309 sprintf(from_str
, "<from?>");
310 if (!inet_ntop(AF_INET
, &to
.sin_addr
, to_str
, sizeof(to_str
)))
311 sprintf(to_str
, "<to?>");
313 zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)",
314 len
, from_str
, to_str
, fd
, ifindex
, ifp
->ifindex
);
317 if (PIM_DEBUG_PIM_PACKETDUMP_RECV
) {
318 pim_pkt_dump(__PRETTY_FUNCTION__
, buf
, len
);
321 #ifdef PIM_CHECK_RECV_IFINDEX_SANITY
322 /* ifindex sanity check */
323 if (ifindex
!= (int) ifp
->ifindex
) {
326 struct interface
*recv_ifp
;
328 if (!inet_ntop(AF_INET
, &from
.sin_addr
, from_str
, sizeof(from_str
)))
329 sprintf(from_str
, "<from?>");
330 if (!inet_ntop(AF_INET
, &to
.sin_addr
, to_str
, sizeof(to_str
)))
331 sprintf(to_str
, "<to?>");
333 recv_ifp
= if_lookup_by_index(ifindex
);
335 zassert(ifindex
== (int) recv_ifp
->ifindex
);
338 #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
339 zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
340 from_str
, to_str
, fd
,
341 ifindex
, recv_ifp
? recv_ifp
->name
: "<if-notfound>",
342 ifp
->ifindex
, ifp
->name
);
348 int fail
= pim_pim_packet(ifp
, buf
, len
);
350 if (PIM_DEBUG_PIM_PACKETS
)
351 zlog_debug("%s: pim_pim_packet() return=%d",
352 __PRETTY_FUNCTION__
, fail
);
356 result
= 0; /* good */
359 pim_sock_read_on(ifp
);
362 ++pim_ifp
->pim_ifstat_hello_recvfail
;
368 static void pim_sock_read_on(struct interface
*ifp
)
370 struct pim_interface
*pim_ifp
;
377 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
378 zlog_debug("Scheduling READ event on PIM socket fd=%d",
379 pim_ifp
->pim_sock_fd
);
381 pim_ifp
->t_pim_sock_read
= 0;
382 zassert(!pim_ifp
->t_pim_sock_read
);
383 THREAD_READ_ON(master
, pim_ifp
->t_pim_sock_read
, pim_sock_read
, ifp
,
384 pim_ifp
->pim_sock_fd
);
387 static int pim_sock_open(struct in_addr ifaddr
, ifindex_t ifindex
)
391 fd
= pim_socket_mcast(IPPROTO_PIM
, ifaddr
, ifindex
, 0 /* loop=false */);
395 if (pim_socket_join(fd
, qpim_all_pim_routers_addr
, ifaddr
, ifindex
)) {
403 void pim_ifstat_reset(struct interface
*ifp
)
405 struct pim_interface
*pim_ifp
;
414 pim_ifp
->pim_ifstat_start
= pim_time_monotonic_sec();
415 pim_ifp
->pim_ifstat_hello_sent
= 0;
416 pim_ifp
->pim_ifstat_hello_sendfail
= 0;
417 pim_ifp
->pim_ifstat_hello_recv
= 0;
418 pim_ifp
->pim_ifstat_hello_recvfail
= 0;
421 void pim_sock_reset(struct interface
*ifp
)
423 struct pim_interface
*pim_ifp
;
430 pim_ifp
->primary_address
= pim_find_primary_addr(ifp
);
432 pim_ifp
->pim_sock_fd
= -1;
433 pim_ifp
->pim_sock_creation
= 0;
434 pim_ifp
->t_pim_sock_read
= 0;
436 pim_ifp
->t_pim_hello_timer
= 0;
437 pim_ifp
->pim_hello_period
= PIM_DEFAULT_HELLO_PERIOD
;
438 pim_ifp
->pim_default_holdtime
= -1; /* unset: means 3.5 * pim_hello_period */
439 pim_ifp
->pim_triggered_hello_delay
= PIM_DEFAULT_TRIGGERED_HELLO_DELAY
;
440 pim_ifp
->pim_dr_priority
= PIM_DEFAULT_DR_PRIORITY
;
441 pim_ifp
->pim_propagation_delay_msec
= PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
442 pim_ifp
->pim_override_interval_msec
= PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
443 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION
) {
444 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
);
447 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
);
450 /* neighbors without lan_delay */
451 pim_ifp
->pim_number_of_nonlandelay_neighbors
= 0;
452 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
= 0;
453 pim_ifp
->pim_neighbors_highest_override_interval_msec
= 0;
456 pim_ifp
->pim_dr_election_last
= 0; /* timestamp */
457 pim_ifp
->pim_dr_election_count
= 0;
458 pim_ifp
->pim_dr_election_changes
= 0;
459 pim_ifp
->pim_dr_num_nondrpri_neighbors
= 0; /* neighbors without dr_pri */
460 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
462 pim_ifstat_reset(ifp
);
465 int pim_msg_send(int fd
,
472 struct sockaddr_in to
;
475 if (PIM_DEBUG_PIM_PACKETS
) {
477 pim_inet4_dump("<dst?>", dst
, dst_str
, sizeof(dst_str
));
478 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
480 dst_str
, ifname
, pim_msg_size
,
481 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg
));
484 memset(&to
, 0, sizeof(to
));
485 to
.sin_family
= AF_INET
;
489 if (PIM_DEBUG_PIM_PACKETDUMP_SEND
) {
490 pim_pkt_dump(__PRETTY_FUNCTION__
, pim_msg
, pim_msg_size
);
493 sent
= sendto(fd
, pim_msg
, pim_msg_size
, MSG_DONTWAIT
,
494 (struct sockaddr
*)&to
, tolen
);
495 if (sent
!= (ssize_t
) pim_msg_size
) {
498 pim_inet4_dump("<dst?>", dst
, dst_str
, sizeof(dst_str
));
500 zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
502 dst_str
, ifname
, fd
, pim_msg_size
,
503 e
, safe_strerror(e
));
506 zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
517 static int hello_send(struct interface
*ifp
,
520 uint8_t pim_msg
[PIM_PIM_BUFSIZE_WRITE
];
521 struct pim_interface
*pim_ifp
;
527 if (PIM_DEBUG_PIM_HELLO
) {
529 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr
, dst_str
, sizeof(dst_str
));
530 zlog_debug("%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",
534 pim_ifp
->pim_propagation_delay_msec
, pim_ifp
->pim_override_interval_msec
,
535 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
),
536 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
537 listcount(ifp
->connected
));
540 pim_tlv_size
= pim_hello_build_tlv(ifp
->name
,
541 pim_msg
+ PIM_PIM_MIN_LEN
,
542 sizeof(pim_msg
) - PIM_PIM_MIN_LEN
,
544 pim_ifp
->pim_dr_priority
,
545 pim_ifp
->pim_generation_id
,
546 pim_ifp
->pim_propagation_delay_msec
,
547 pim_ifp
->pim_override_interval_msec
,
548 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
),
550 if (pim_tlv_size
< 0) {
554 pim_msg_size
= pim_tlv_size
+ PIM_PIM_MIN_LEN
;
556 zassert(pim_msg_size
>= PIM_PIM_MIN_LEN
);
557 zassert(pim_msg_size
<= PIM_PIM_BUFSIZE_WRITE
);
559 pim_msg_build_header(pim_msg
, pim_msg_size
,
562 if (pim_msg_send(pim_ifp
->pim_sock_fd
,
563 qpim_all_pim_routers_addr
,
567 if (PIM_DEBUG_PIM_HELLO
) {
568 zlog_debug("%s: could not send PIM message on interface %s",
569 __PRETTY_FUNCTION__
, ifp
->name
);
577 static int pim_hello_send(struct interface
*ifp
,
580 struct pim_interface
*pim_ifp
;
586 if (if_is_loopback (ifp
))
589 if (hello_send(ifp
, holdtime
)) {
590 ++pim_ifp
->pim_ifstat_hello_sendfail
;
592 if (PIM_DEBUG_PIM_HELLO
) {
593 zlog_warn("Could not send PIM hello on interface %s",
599 ++pim_ifp
->pim_ifstat_hello_sent
;
604 static void hello_resched(struct interface
*ifp
)
606 struct pim_interface
*pim_ifp
;
612 if (PIM_DEBUG_PIM_HELLO
) {
613 zlog_debug("Rescheduling %d sec hello on interface %s",
614 pim_ifp
->pim_hello_period
, ifp
->name
);
616 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
617 THREAD_TIMER_ON(master
, pim_ifp
->t_pim_hello_timer
,
619 ifp
, pim_ifp
->pim_hello_period
);
625 static int on_pim_hello_send(struct thread
*t
)
627 struct pim_interface
*pim_ifp
;
628 struct interface
*ifp
;
637 * Schedule next hello
639 pim_ifp
->t_pim_hello_timer
= 0;
645 return pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
649 RFC 4601: 4.3.1. Sending Hello Messages
651 Thus, if a router needs to send a Join/Prune or Assert message on an
652 interface on which it has not yet sent a Hello message with the
653 currently configured IP address, then it MUST immediately send the
654 relevant Hello message without waiting for the Hello Timer to
655 expire, followed by the Join/Prune or Assert message.
657 void pim_hello_restart_now(struct interface
*ifp
)
659 struct pim_interface
*pim_ifp
;
666 * Reset next hello timer
671 * Immediately send hello
673 pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
677 RFC 4601: 4.3.1. Sending Hello Messages
679 To allow new or rebooting routers to learn of PIM neighbors quickly,
680 when a Hello message is received from a new neighbor, or a Hello
681 message with a new GenID is received from an existing neighbor, a
682 new Hello message should be sent on this interface after a
683 randomized delay between 0 and Triggered_Hello_Delay.
685 void pim_hello_restart_triggered(struct interface
*ifp
)
687 struct pim_interface
*pim_ifp
;
688 int triggered_hello_delay_msec
;
695 triggered_hello_delay_msec
= 1000 * pim_ifp
->pim_triggered_hello_delay
;
697 if (pim_ifp
->t_pim_hello_timer
) {
698 long remain_msec
= pim_time_timer_remain_msec(pim_ifp
->t_pim_hello_timer
);
699 if (remain_msec
<= triggered_hello_delay_msec
) {
700 /* Rescheduling hello would increase the delay, then it's faster
701 to just wait for the scheduled periodic hello. */
705 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
706 pim_ifp
->t_pim_hello_timer
= 0;
708 zassert(!pim_ifp
->t_pim_hello_timer
);
710 random_msec
= random() % (triggered_hello_delay_msec
+ 1);
712 if (PIM_DEBUG_PIM_HELLO
) {
713 zlog_debug("Scheduling %d msec triggered hello on interface %s",
714 random_msec
, ifp
->name
);
717 THREAD_TIMER_MSEC_ON(master
, pim_ifp
->t_pim_hello_timer
,
722 int pim_sock_add(struct interface
*ifp
)
724 struct pim_interface
*pim_ifp
;
725 struct in_addr ifaddr
;
731 if (pim_ifp
->pim_sock_fd
>= 0) {
732 zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
733 pim_ifp
->pim_sock_fd
, ifp
->name
);
737 ifaddr
= pim_ifp
->primary_address
;
739 pim_ifp
->pim_sock_fd
= pim_sock_open(ifaddr
, ifp
->ifindex
);
740 if (pim_ifp
->pim_sock_fd
< 0) {
741 zlog_warn("Could not open PIM socket on interface %s",
746 pim_ifp
->t_pim_sock_read
= 0;
747 pim_ifp
->pim_sock_creation
= pim_time_monotonic_sec();
750 * Just ensure that the new generation id
751 * actually chooses something different.
752 * Actually ran across a case where this
753 * happened, pre-switch to random().
754 * While this is unlikely to happen now
755 * let's make sure it doesn't.
757 old_genid
= pim_ifp
->pim_generation_id
;
759 while (old_genid
== pim_ifp
->pim_generation_id
)
760 pim_ifp
->pim_generation_id
= random();
762 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
763 ifp
->name
, ifp
->ifindex
);
766 * Start receiving PIM messages
768 pim_sock_read_on(ifp
);
771 * Start sending PIM hello's
773 pim_hello_restart_triggered(ifp
);