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,
20 $QuaggaId: $Format:%an, %ai, %h$ $
33 #include "pim_iface.h"
38 #include "pim_neighbor.h"
39 #include "pim_hello.h"
41 #include "pim_assert.h"
43 #include "pim_register.h"
45 static int on_pim_hello_send(struct thread
*t
);
46 static int pim_hello_send(struct interface
*ifp
,
49 static void sock_close(struct interface
*ifp
)
51 struct pim_interface
*pim_ifp
= ifp
->info
;
53 if (PIM_DEBUG_PIM_TRACE
) {
54 if (pim_ifp
->t_pim_sock_read
) {
55 zlog_debug("Cancelling READ event for PIM socket fd=%d on interface %s",
60 THREAD_OFF(pim_ifp
->t_pim_sock_read
);
62 if (PIM_DEBUG_PIM_TRACE
) {
63 if (pim_ifp
->t_pim_hello_timer
) {
64 zlog_debug("Cancelling PIM hello timer for interface %s",
68 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
70 if (PIM_DEBUG_PIM_TRACE
) {
71 zlog_debug("Deleting PIM socket fd=%d on interface %s",
72 pim_ifp
->pim_sock_fd
, ifp
->name
);
75 if (close(pim_ifp
->pim_sock_fd
)) {
76 zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
77 pim_ifp
->pim_sock_fd
, ifp
->name
,
78 errno
, safe_strerror(errno
));
81 pim_ifp
->pim_sock_fd
= -1;
82 pim_ifp
->pim_sock_creation
= 0;
84 zassert(pim_ifp
->pim_sock_fd
< 0);
85 zassert(!pim_ifp
->t_pim_sock_read
);
86 zassert(!pim_ifp
->t_pim_hello_timer
);
87 zassert(!pim_ifp
->pim_sock_creation
);
90 void pim_sock_delete(struct interface
*ifp
, const char *delete_message
)
92 zlog_info("PIM INTERFACE DOWN: on interface %s: %s",
93 ifp
->name
, delete_message
);
96 zlog_err("%s: %s: but PIM not enabled on interface %s (!)",
97 __PRETTY_FUNCTION__
, delete_message
, ifp
->name
);
102 RFC 4601: 4.3.1. Sending Hello Messages
104 Before an interface goes down or changes primary IP address, a Hello
105 message with a zero HoldTime should be sent immediately (with the
106 old IP address if the IP address changed).
108 pim_hello_send(ifp
, 0 /* zero-sec holdtime */);
110 pim_neighbor_delete_all(ifp
, delete_message
);
115 int pim_pim_packet(struct interface
*ifp
, uint8_t *buf
, size_t len
)
118 size_t ip_hlen
; /* ip header length in bytes */
125 uint16_t pim_checksum
; /* received checksum */
126 uint16_t checksum
; /* computed checksum */
127 struct pim_neighbor
*neigh
;
130 zlog_warn("%s: PIM not enabled on interface %s",
131 __PRETTY_FUNCTION__
, ifp
->name
);
135 if (len
< sizeof(*ip_hdr
)) {
136 zlog_warn("PIM packet size=%zu shorter than minimum=%zu",
137 len
, sizeof(*ip_hdr
));
141 ip_hdr
= (struct ip
*) buf
;
143 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, src_str
, sizeof(src_str
));
144 pim_inet4_dump("<dst?>", ip_hdr
->ip_dst
, dst_str
, sizeof(dst_str
));
146 ip_hlen
= ip_hdr
->ip_hl
<< 2; /* ip_hl gives length in 4-byte words */
148 if (PIM_DEBUG_PIM_PACKETS
) {
149 zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d",
150 src_str
, dst_str
, ifp
->name
, len
, ip_hlen
, ip_hdr
->ip_p
);
153 if (ip_hdr
->ip_p
!= PIM_IP_PROTO_PIM
) {
154 zlog_warn("IP packet protocol=%d is not PIM=%d",
155 ip_hdr
->ip_p
, PIM_IP_PROTO_PIM
);
159 if (ip_hlen
< PIM_IP_HEADER_MIN_LEN
) {
160 zlog_warn("IP packet header size=%zu shorter than minimum=%d",
161 ip_hlen
, PIM_IP_HEADER_MIN_LEN
);
164 if (ip_hlen
> PIM_IP_HEADER_MAX_LEN
) {
165 zlog_warn("IP packet header size=%zu greater than maximum=%d",
166 ip_hlen
, PIM_IP_HEADER_MAX_LEN
);
170 pim_msg
= buf
+ ip_hlen
;
171 pim_msg_len
= len
- ip_hlen
;
173 if (PIM_DEBUG_PIM_PACKETDUMP_RECV
) {
174 pim_pkt_dump(__PRETTY_FUNCTION__
, pim_msg
, pim_msg_len
);
177 if (pim_msg_len
< PIM_PIM_MIN_LEN
) {
178 zlog_warn("PIM message size=%d shorter than minimum=%d",
179 pim_msg_len
, PIM_PIM_MIN_LEN
);
183 pim_version
= PIM_MSG_HDR_GET_VERSION(pim_msg
);
184 pim_type
= PIM_MSG_HDR_GET_TYPE(pim_msg
);
186 if (pim_version
!= PIM_PROTO_VERSION
) {
187 zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d",
188 ifp
->name
, pim_version
);
192 /* save received checksum */
193 pim_checksum
= PIM_MSG_HDR_GET_CHECKSUM(pim_msg
);
195 /* for computing checksum */
196 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg
) = 0;
198 checksum
= in_cksum(pim_msg
, pim_msg_len
);
199 if (checksum
!= pim_checksum
) {
200 zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
201 ifp
->name
, pim_checksum
, checksum
);
205 if (PIM_DEBUG_PIM_PACKETS
) {
206 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",
207 src_str
, dst_str
, ifp
->name
, ip_hdr
->ip_ttl
,
208 pim_version
, pim_type
, pim_msg_len
, checksum
);
211 if (pim_type
== PIM_MSG_TYPE_REG_STOP
||
212 pim_type
== PIM_MSG_TYPE_BOOTSTRAP
||
213 pim_type
== PIM_MSG_TYPE_GRAFT
||
214 pim_type
== PIM_MSG_TYPE_GRAFT_ACK
||
215 pim_type
== PIM_MSG_TYPE_CANDIDATE
)
217 if (PIM_DEBUG_PIM_PACKETS
) {
218 zlog_debug("Recv PIM packet type %d which is not currently understood",
224 if (pim_type
== PIM_MSG_TYPE_HELLO
) {
225 return pim_hello_recv(ifp
,
227 pim_msg
+ PIM_MSG_HEADER_LEN
,
228 pim_msg_len
- PIM_MSG_HEADER_LEN
);
229 } else if (pim_type
== PIM_MSG_TYPE_REGISTER
) {
230 return pim_register_recv(ifp
,
233 pim_msg
+ PIM_MSG_HEADER_LEN
,
234 pim_msg_len
- PIM_MSG_HEADER_LEN
);
237 neigh
= pim_neighbor_find(ifp
, ip_hdr
->ip_src
);
239 zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
240 __FILE__
, __PRETTY_FUNCTION__
,
241 pim_type
, src_str
, ifp
->name
);
246 case PIM_MSG_TYPE_JOIN_PRUNE
:
247 return pim_joinprune_recv(ifp
, neigh
,
249 pim_msg
+ PIM_MSG_HEADER_LEN
,
250 pim_msg_len
- PIM_MSG_HEADER_LEN
);
252 case PIM_MSG_TYPE_ASSERT
:
253 return pim_assert_recv(ifp
, neigh
,
255 pim_msg
+ PIM_MSG_HEADER_LEN
,
256 pim_msg_len
- PIM_MSG_HEADER_LEN
);
259 zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s",
260 __FILE__
, __PRETTY_FUNCTION__
,
261 pim_type
, src_str
, ifp
->name
);
268 static void pim_sock_read_on(struct interface
*ifp
);
270 static int pim_sock_read(struct thread
*t
)
272 struct interface
*ifp
;
273 struct pim_interface
*pim_ifp
;
275 struct sockaddr_in from
;
276 struct sockaddr_in to
;
277 socklen_t fromlen
= sizeof(from
);
278 socklen_t tolen
= sizeof(to
);
279 uint8_t buf
[PIM_PIM_BUFSIZE_READ
];
281 ifindex_t ifindex
= -1;
282 int result
= -1; /* defaults to bad */
294 zassert(fd
== pim_ifp
->pim_sock_fd
);
296 len
= pim_socket_recvfromto(fd
, buf
, sizeof(buf
),
301 zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s",
302 fd
, errno
, safe_strerror(errno
));
306 if (PIM_DEBUG_PIM_PACKETS
) {
310 if (!inet_ntop(AF_INET
, &from
.sin_addr
, from_str
, sizeof(from_str
)))
311 sprintf(from_str
, "<from?>");
312 if (!inet_ntop(AF_INET
, &to
.sin_addr
, to_str
, sizeof(to_str
)))
313 sprintf(to_str
, "<to?>");
315 zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)",
316 len
, from_str
, to_str
, fd
, ifindex
, ifp
->ifindex
);
319 if (PIM_DEBUG_PIM_PACKETDUMP_RECV
) {
320 pim_pkt_dump(__PRETTY_FUNCTION__
, buf
, len
);
323 #ifdef PIM_CHECK_RECV_IFINDEX_SANITY
324 /* ifindex sanity check */
325 if (ifindex
!= (int) ifp
->ifindex
) {
328 struct interface
*recv_ifp
;
330 if (!inet_ntop(AF_INET
, &from
.sin_addr
, from_str
, sizeof(from_str
)))
331 sprintf(from_str
, "<from?>");
332 if (!inet_ntop(AF_INET
, &to
.sin_addr
, to_str
, sizeof(to_str
)))
333 sprintf(to_str
, "<to?>");
335 recv_ifp
= if_lookup_by_index(ifindex
);
337 zassert(ifindex
== (int) recv_ifp
->ifindex
);
340 #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
341 zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
342 from_str
, to_str
, fd
,
343 ifindex
, recv_ifp
? recv_ifp
->name
: "<if-notfound>",
344 ifp
->ifindex
, ifp
->name
);
350 int fail
= pim_pim_packet(ifp
, buf
, len
);
352 if (PIM_DEBUG_PIM_PACKETS
)
353 zlog_debug("%s: pim_pim_packet() return=%d",
354 __PRETTY_FUNCTION__
, fail
);
358 result
= 0; /* good */
361 pim_sock_read_on(ifp
);
364 ++pim_ifp
->pim_ifstat_hello_recvfail
;
370 static void pim_sock_read_on(struct interface
*ifp
)
372 struct pim_interface
*pim_ifp
;
379 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
380 zlog_debug("Scheduling READ event on PIM socket fd=%d",
381 pim_ifp
->pim_sock_fd
);
383 pim_ifp
->t_pim_sock_read
= 0;
384 zassert(!pim_ifp
->t_pim_sock_read
);
385 THREAD_READ_ON(master
, pim_ifp
->t_pim_sock_read
, pim_sock_read
, ifp
,
386 pim_ifp
->pim_sock_fd
);
389 static int pim_sock_open(struct in_addr ifaddr
, ifindex_t ifindex
)
393 fd
= pim_socket_mcast(IPPROTO_PIM
, ifaddr
, ifindex
, 0 /* loop=false */);
397 if (pim_socket_join(fd
, qpim_all_pim_routers_addr
, ifaddr
, ifindex
)) {
405 void pim_ifstat_reset(struct interface
*ifp
)
407 struct pim_interface
*pim_ifp
;
416 pim_ifp
->pim_ifstat_start
= pim_time_monotonic_sec();
417 pim_ifp
->pim_ifstat_hello_sent
= 0;
418 pim_ifp
->pim_ifstat_hello_sendfail
= 0;
419 pim_ifp
->pim_ifstat_hello_recv
= 0;
420 pim_ifp
->pim_ifstat_hello_recvfail
= 0;
423 void pim_sock_reset(struct interface
*ifp
)
425 struct pim_interface
*pim_ifp
;
432 pim_ifp
->primary_address
= pim_find_primary_addr(ifp
);
434 pim_ifp
->pim_sock_fd
= -1;
435 pim_ifp
->pim_sock_creation
= 0;
436 pim_ifp
->t_pim_sock_read
= 0;
438 pim_ifp
->t_pim_hello_timer
= 0;
439 pim_ifp
->pim_hello_period
= PIM_DEFAULT_HELLO_PERIOD
;
440 pim_ifp
->pim_default_holdtime
= -1; /* unset: means 3.5 * pim_hello_period */
441 pim_ifp
->pim_triggered_hello_delay
= PIM_DEFAULT_TRIGGERED_HELLO_DELAY
;
442 pim_ifp
->pim_dr_priority
= PIM_DEFAULT_DR_PRIORITY
;
443 pim_ifp
->pim_propagation_delay_msec
= PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
444 pim_ifp
->pim_override_interval_msec
= PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
445 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION
) {
446 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
);
449 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
);
452 /* neighbors without lan_delay */
453 pim_ifp
->pim_number_of_nonlandelay_neighbors
= 0;
454 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
= 0;
455 pim_ifp
->pim_neighbors_highest_override_interval_msec
= 0;
458 pim_ifp
->pim_dr_election_last
= 0; /* timestamp */
459 pim_ifp
->pim_dr_election_count
= 0;
460 pim_ifp
->pim_dr_election_changes
= 0;
461 pim_ifp
->pim_dr_num_nondrpri_neighbors
= 0; /* neighbors without dr_pri */
462 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
464 pim_ifstat_reset(ifp
);
467 int pim_msg_send(int fd
,
474 struct sockaddr_in to
;
477 if (PIM_DEBUG_PIM_PACKETS
) {
479 pim_inet4_dump("<dst?>", dst
, dst_str
, sizeof(dst_str
));
480 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
482 dst_str
, ifname
, pim_msg_size
,
483 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg
));
486 memset(&to
, 0, sizeof(to
));
487 to
.sin_family
= AF_INET
;
491 if (PIM_DEBUG_PIM_PACKETDUMP_SEND
) {
492 pim_pkt_dump(__PRETTY_FUNCTION__
, pim_msg
, pim_msg_size
);
495 sent
= sendto(fd
, pim_msg
, pim_msg_size
, MSG_DONTWAIT
,
496 (struct sockaddr
*)&to
, tolen
);
497 if (sent
!= (ssize_t
) pim_msg_size
) {
499 pim_inet4_dump("<dst?>", dst
, dst_str
, sizeof(dst_str
));
501 zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
503 dst_str
, ifname
, fd
, pim_msg_size
,
504 errno
, safe_strerror(errno
));
507 zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
518 static int hello_send(struct interface
*ifp
,
521 uint8_t pim_msg
[PIM_PIM_BUFSIZE_WRITE
];
522 struct pim_interface
*pim_ifp
;
528 if (PIM_DEBUG_PIM_HELLO
) {
530 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr
, dst_str
, sizeof(dst_str
));
531 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",
535 pim_ifp
->pim_propagation_delay_msec
, pim_ifp
->pim_override_interval_msec
,
536 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
),
537 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
538 listcount(ifp
->connected
));
541 pim_tlv_size
= pim_hello_build_tlv(ifp
->name
,
542 pim_msg
+ PIM_PIM_MIN_LEN
,
543 sizeof(pim_msg
) - PIM_PIM_MIN_LEN
,
545 pim_ifp
->pim_dr_priority
,
546 pim_ifp
->pim_generation_id
,
547 pim_ifp
->pim_propagation_delay_msec
,
548 pim_ifp
->pim_override_interval_msec
,
549 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
),
551 if (pim_tlv_size
< 0) {
555 pim_msg_size
= pim_tlv_size
+ PIM_PIM_MIN_LEN
;
557 zassert(pim_msg_size
>= PIM_PIM_MIN_LEN
);
558 zassert(pim_msg_size
<= PIM_PIM_BUFSIZE_WRITE
);
560 pim_msg_build_header(pim_msg
, pim_msg_size
,
563 if (pim_msg_send(pim_ifp
->pim_sock_fd
,
564 qpim_all_pim_routers_addr
,
568 if (PIM_DEBUG_PIM_HELLO
) {
569 zlog_debug("%s: could not send PIM message on interface %s",
570 __PRETTY_FUNCTION__
, ifp
->name
);
578 static int pim_hello_send(struct interface
*ifp
,
581 struct pim_interface
*pim_ifp
;
587 if (if_is_loopback (ifp
))
590 if (hello_send(ifp
, holdtime
)) {
591 ++pim_ifp
->pim_ifstat_hello_sendfail
;
593 if (PIM_DEBUG_PIM_HELLO
) {
594 zlog_warn("Could not send PIM hello on interface %s",
600 ++pim_ifp
->pim_ifstat_hello_sent
;
605 static void hello_resched(struct interface
*ifp
)
607 struct pim_interface
*pim_ifp
;
613 if (PIM_DEBUG_PIM_HELLO
) {
614 zlog_debug("Rescheduling %d sec hello on interface %s",
615 pim_ifp
->pim_hello_period
, ifp
->name
);
617 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
618 THREAD_TIMER_ON(master
, pim_ifp
->t_pim_hello_timer
,
620 ifp
, pim_ifp
->pim_hello_period
);
626 static int on_pim_hello_send(struct thread
*t
)
628 struct pim_interface
*pim_ifp
;
629 struct interface
*ifp
;
638 * Schedule next hello
640 pim_ifp
->t_pim_hello_timer
= 0;
646 return pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
650 RFC 4601: 4.3.1. Sending Hello Messages
652 Thus, if a router needs to send a Join/Prune or Assert message on an
653 interface on which it has not yet sent a Hello message with the
654 currently configured IP address, then it MUST immediately send the
655 relevant Hello message without waiting for the Hello Timer to
656 expire, followed by the Join/Prune or Assert message.
658 void pim_hello_restart_now(struct interface
*ifp
)
660 struct pim_interface
*pim_ifp
;
667 * Reset next hello timer
672 * Immediately send hello
674 pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
678 RFC 4601: 4.3.1. Sending Hello Messages
680 To allow new or rebooting routers to learn of PIM neighbors quickly,
681 when a Hello message is received from a new neighbor, or a Hello
682 message with a new GenID is received from an existing neighbor, a
683 new Hello message should be sent on this interface after a
684 randomized delay between 0 and Triggered_Hello_Delay.
686 void pim_hello_restart_triggered(struct interface
*ifp
)
688 struct pim_interface
*pim_ifp
;
689 int triggered_hello_delay_msec
;
696 triggered_hello_delay_msec
= 1000 * pim_ifp
->pim_triggered_hello_delay
;
698 if (pim_ifp
->t_pim_hello_timer
) {
699 long remain_msec
= pim_time_timer_remain_msec(pim_ifp
->t_pim_hello_timer
);
700 if (remain_msec
<= triggered_hello_delay_msec
) {
701 /* Rescheduling hello would increase the delay, then it's faster
702 to just wait for the scheduled periodic hello. */
706 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
707 pim_ifp
->t_pim_hello_timer
= 0;
709 zassert(!pim_ifp
->t_pim_hello_timer
);
711 random_msec
= random() % (triggered_hello_delay_msec
+ 1);
713 if (PIM_DEBUG_PIM_HELLO
) {
714 zlog_debug("Scheduling %d msec triggered hello on interface %s",
715 random_msec
, ifp
->name
);
718 THREAD_TIMER_MSEC_ON(master
, pim_ifp
->t_pim_hello_timer
,
723 int pim_sock_add(struct interface
*ifp
)
725 struct pim_interface
*pim_ifp
;
726 struct in_addr ifaddr
;
732 if (pim_ifp
->pim_sock_fd
>= 0) {
733 zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
734 pim_ifp
->pim_sock_fd
, ifp
->name
);
738 ifaddr
= pim_ifp
->primary_address
;
740 pim_ifp
->pim_sock_fd
= pim_sock_open(ifaddr
, ifp
->ifindex
);
741 if (pim_ifp
->pim_sock_fd
< 0) {
742 zlog_warn("Could not open PIM socket on interface %s",
747 pim_ifp
->t_pim_sock_read
= 0;
748 pim_ifp
->pim_sock_creation
= pim_time_monotonic_sec();
751 * Just ensure that the new generation id
752 * actually chooses something different.
753 * Actually ran across a case where this
754 * happened, pre-switch to random().
755 * While this is unlikely to happen now
756 * let's make sure it doesn't.
758 old_genid
= pim_ifp
->pim_generation_id
;
760 while (old_genid
== pim_ifp
->pim_generation_id
)
761 pim_ifp
->pim_generation_id
= random();
763 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
764 ifp
->name
, ifp
->ifindex
);
767 * Start receiving PIM messages
769 pim_sock_read_on(ifp
);
772 * Start sending PIM hello's
774 pim_hello_restart_triggered(ifp
);