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
) {
500 pim_inet4_dump("<dst?>", dst
, dst_str
, sizeof(dst_str
));
502 zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
504 dst_str
, ifname
, fd
, pim_msg_size
,
505 e
, safe_strerror(e
));
508 zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
519 static int hello_send(struct interface
*ifp
,
522 uint8_t pim_msg
[PIM_PIM_BUFSIZE_WRITE
];
523 struct pim_interface
*pim_ifp
;
529 if (PIM_DEBUG_PIM_HELLO
) {
531 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr
, dst_str
, sizeof(dst_str
));
532 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",
536 pim_ifp
->pim_propagation_delay_msec
, pim_ifp
->pim_override_interval_msec
,
537 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
),
538 pim_ifp
->pim_dr_priority
, pim_ifp
->pim_generation_id
,
539 listcount(ifp
->connected
));
542 pim_tlv_size
= pim_hello_build_tlv(ifp
->name
,
543 pim_msg
+ PIM_PIM_MIN_LEN
,
544 sizeof(pim_msg
) - PIM_PIM_MIN_LEN
,
546 pim_ifp
->pim_dr_priority
,
547 pim_ifp
->pim_generation_id
,
548 pim_ifp
->pim_propagation_delay_msec
,
549 pim_ifp
->pim_override_interval_msec
,
550 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
),
552 if (pim_tlv_size
< 0) {
556 pim_msg_size
= pim_tlv_size
+ PIM_PIM_MIN_LEN
;
558 zassert(pim_msg_size
>= PIM_PIM_MIN_LEN
);
559 zassert(pim_msg_size
<= PIM_PIM_BUFSIZE_WRITE
);
561 pim_msg_build_header(pim_msg
, pim_msg_size
,
564 if (pim_msg_send(pim_ifp
->pim_sock_fd
,
565 qpim_all_pim_routers_addr
,
569 if (PIM_DEBUG_PIM_HELLO
) {
570 zlog_debug("%s: could not send PIM message on interface %s",
571 __PRETTY_FUNCTION__
, ifp
->name
);
579 static int pim_hello_send(struct interface
*ifp
,
582 struct pim_interface
*pim_ifp
;
588 if (if_is_loopback (ifp
))
591 if (hello_send(ifp
, holdtime
)) {
592 ++pim_ifp
->pim_ifstat_hello_sendfail
;
594 if (PIM_DEBUG_PIM_HELLO
) {
595 zlog_warn("Could not send PIM hello on interface %s",
601 ++pim_ifp
->pim_ifstat_hello_sent
;
606 static void hello_resched(struct interface
*ifp
)
608 struct pim_interface
*pim_ifp
;
614 if (PIM_DEBUG_PIM_HELLO
) {
615 zlog_debug("Rescheduling %d sec hello on interface %s",
616 pim_ifp
->pim_hello_period
, ifp
->name
);
618 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
619 THREAD_TIMER_ON(master
, pim_ifp
->t_pim_hello_timer
,
621 ifp
, pim_ifp
->pim_hello_period
);
627 static int on_pim_hello_send(struct thread
*t
)
629 struct pim_interface
*pim_ifp
;
630 struct interface
*ifp
;
639 * Schedule next hello
641 pim_ifp
->t_pim_hello_timer
= 0;
647 return pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
651 RFC 4601: 4.3.1. Sending Hello Messages
653 Thus, if a router needs to send a Join/Prune or Assert message on an
654 interface on which it has not yet sent a Hello message with the
655 currently configured IP address, then it MUST immediately send the
656 relevant Hello message without waiting for the Hello Timer to
657 expire, followed by the Join/Prune or Assert message.
659 void pim_hello_restart_now(struct interface
*ifp
)
661 struct pim_interface
*pim_ifp
;
668 * Reset next hello timer
673 * Immediately send hello
675 pim_hello_send(ifp
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
679 RFC 4601: 4.3.1. Sending Hello Messages
681 To allow new or rebooting routers to learn of PIM neighbors quickly,
682 when a Hello message is received from a new neighbor, or a Hello
683 message with a new GenID is received from an existing neighbor, a
684 new Hello message should be sent on this interface after a
685 randomized delay between 0 and Triggered_Hello_Delay.
687 void pim_hello_restart_triggered(struct interface
*ifp
)
689 struct pim_interface
*pim_ifp
;
690 int triggered_hello_delay_msec
;
697 triggered_hello_delay_msec
= 1000 * pim_ifp
->pim_triggered_hello_delay
;
699 if (pim_ifp
->t_pim_hello_timer
) {
700 long remain_msec
= pim_time_timer_remain_msec(pim_ifp
->t_pim_hello_timer
);
701 if (remain_msec
<= triggered_hello_delay_msec
) {
702 /* Rescheduling hello would increase the delay, then it's faster
703 to just wait for the scheduled periodic hello. */
707 THREAD_OFF(pim_ifp
->t_pim_hello_timer
);
708 pim_ifp
->t_pim_hello_timer
= 0;
710 zassert(!pim_ifp
->t_pim_hello_timer
);
712 random_msec
= random() % (triggered_hello_delay_msec
+ 1);
714 if (PIM_DEBUG_PIM_HELLO
) {
715 zlog_debug("Scheduling %d msec triggered hello on interface %s",
716 random_msec
, ifp
->name
);
719 THREAD_TIMER_MSEC_ON(master
, pim_ifp
->t_pim_hello_timer
,
724 int pim_sock_add(struct interface
*ifp
)
726 struct pim_interface
*pim_ifp
;
727 struct in_addr ifaddr
;
733 if (pim_ifp
->pim_sock_fd
>= 0) {
734 zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
735 pim_ifp
->pim_sock_fd
, ifp
->name
);
739 ifaddr
= pim_ifp
->primary_address
;
741 pim_ifp
->pim_sock_fd
= pim_sock_open(ifaddr
, ifp
->ifindex
);
742 if (pim_ifp
->pim_sock_fd
< 0) {
743 zlog_warn("Could not open PIM socket on interface %s",
748 pim_ifp
->t_pim_sock_read
= 0;
749 pim_ifp
->pim_sock_creation
= pim_time_monotonic_sec();
752 * Just ensure that the new generation id
753 * actually chooses something different.
754 * Actually ran across a case where this
755 * happened, pre-switch to random().
756 * While this is unlikely to happen now
757 * let's make sure it doesn't.
759 old_genid
= pim_ifp
->pim_generation_id
;
761 while (old_genid
== pim_ifp
->pim_generation_id
)
762 pim_ifp
->pim_generation_id
= random();
764 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
765 ifp
->name
, ifp
->ifindex
);
768 * Start receiving PIM messages
770 pim_sock_read_on(ifp
);
773 * Start sending PIM hello's
775 pim_hello_restart_triggered(ifp
);