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$ $
32 #include "pim_iface.h"
37 #include "pim_neighbor.h"
38 #include "pim_hello.h"
40 #include "pim_assert.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_REGISTER ||
210 pim_type == PIM_MSG_TYPE_REG_STOP ||
211 pim_type == PIM_MSG_TYPE_BOOTSTRAP ||
212 pim_type == PIM_MSG_TYPE_GRAFT ||
213 pim_type == PIM_MSG_TYPE_GRAFT_ACK ||
214 pim_type == PIM_MSG_TYPE_CANDIDATE)
216 if (PIM_DEBUG_PIM_PACKETS) {
217 zlog_debug("Recv PIM packet type %d which is not currently understood",
223 if (pim_type == PIM_MSG_TYPE_HELLO) {
224 int result = pim_hello_recv(ifp,
226 pim_msg + PIM_MSG_HEADER_LEN,
227 pim_msg_len - PIM_MSG_HEADER_LEN);
231 neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
233 zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
234 __FILE__, __PRETTY_FUNCTION__,
235 pim_type, src_str, ifp->name);
240 case PIM_MSG_TYPE_JOIN_PRUNE:
241 return pim_joinprune_recv(ifp, neigh,
243 pim_msg + PIM_MSG_HEADER_LEN,
244 pim_msg_len - PIM_MSG_HEADER_LEN);
245 case PIM_MSG_TYPE_ASSERT:
246 return pim_assert_recv(ifp, neigh,
248 pim_msg + PIM_MSG_HEADER_LEN,
249 pim_msg_len - PIM_MSG_HEADER_LEN);
251 zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s",
252 __FILE__, __PRETTY_FUNCTION__,
253 pim_type, src_str, ifp->name);
259 static void pim_sock_read_on(struct interface *ifp);
261 static int pim_sock_read(struct thread *t)
263 struct interface *ifp;
264 struct pim_interface *pim_ifp;
266 struct sockaddr_in from;
267 struct sockaddr_in to;
268 socklen_t fromlen = sizeof(from);
269 socklen_t tolen = sizeof(to);
270 uint8_t buf[PIM_PIM_BUFSIZE_READ];
272 ifindex_t ifindex = -1;
273 int result = -1; /* defaults to bad */
285 zassert(fd == pim_ifp->pim_sock_fd);
287 len = pim_socket_recvfromto(fd, buf, sizeof(buf),
292 zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s",
293 fd, errno, safe_strerror(errno));
297 if (PIM_DEBUG_PIM_PACKETS) {
301 if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str)))
302 sprintf(from_str, "<from?>");
303 if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str)))
304 sprintf(to_str, "<to?>");
306 zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)",
307 len, from_str, to_str, fd, ifindex, ifp->ifindex);
310 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
311 pim_pkt_dump(__PRETTY_FUNCTION__, buf, len);
314 #ifdef PIM_CHECK_RECV_IFINDEX_SANITY
315 /* ifindex sanity check */
316 if (ifindex != (int) ifp->ifindex) {
319 struct interface *recv_ifp;
321 if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
322 sprintf(from_str, "<from?>");
323 if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
324 sprintf(to_str, "<to?>");
326 recv_ifp = if_lookup_by_index(ifindex);
328 zassert(ifindex == (int) recv_ifp->ifindex);
331 #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
332 zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
333 from_str, to_str, fd,
334 ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
335 ifp->ifindex, ifp->name);
341 int fail = pim_pim_packet(ifp, buf, len);
343 zlog_warn("%s: pim_pim_packet() return=%d",
344 __PRETTY_FUNCTION__, fail);
348 result = 0; /* good */
351 pim_sock_read_on(ifp);
354 ++pim_ifp->pim_ifstat_hello_recvfail;
360 static void pim_sock_read_on(struct interface *ifp)
362 struct pim_interface *pim_ifp;
369 if (PIM_DEBUG_PIM_TRACE) {
370 zlog_debug("Scheduling READ event on PIM socket fd=%d",
371 pim_ifp->pim_sock_fd);
373 pim_ifp->t_pim_sock_read = 0;
374 zassert(!pim_ifp->t_pim_sock_read);
375 THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
376 pim_ifp->pim_sock_fd);
379 static int pim_sock_open(struct in_addr ifaddr, ifindex_t ifindex)
383 fd = pim_socket_mcast(IPPROTO_PIM, ifaddr, 0 /* loop=false */);
387 if (pim_socket_join(fd, qpim_all_pim_routers_addr, ifaddr, ifindex)) {
395 void pim_ifstat_reset(struct interface *ifp)
397 struct pim_interface *pim_ifp;
406 pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
407 pim_ifp->pim_ifstat_hello_sent = 0;
408 pim_ifp->pim_ifstat_hello_sendfail = 0;
409 pim_ifp->pim_ifstat_hello_recv = 0;
410 pim_ifp->pim_ifstat_hello_recvfail = 0;
413 void pim_sock_reset(struct interface *ifp)
415 struct pim_interface *pim_ifp;
422 pim_ifp->primary_address = pim_find_primary_addr(ifp);
424 pim_ifp->pim_sock_fd = -1;
425 pim_ifp->pim_sock_creation = 0;
426 pim_ifp->t_pim_sock_read = 0;
428 pim_ifp->t_pim_hello_timer = 0;
429 pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
430 pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
431 pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
432 pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
433 pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
434 pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
435 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
436 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
439 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
442 /* neighbors without lan_delay */
443 pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
444 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
445 pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
448 pim_ifp->pim_dr_election_last = 0; /* timestamp */
449 pim_ifp->pim_dr_election_count = 0;
450 pim_ifp->pim_dr_election_changes = 0;
451 pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */
452 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
454 pim_ifstat_reset(ifp);
457 int pim_msg_send(int fd,
464 struct sockaddr_in to;
467 if (PIM_DEBUG_PIM_PACKETS) {
469 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
470 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
472 dst_str, ifname, pim_msg_size,
473 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg));
476 memset(&to, 0, sizeof(to));
477 to.sin_family = AF_INET;
481 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
482 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
485 sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT,
486 (struct sockaddr *)&to, tolen);
487 if (sent != (ssize_t) pim_msg_size) {
490 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
492 zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
494 dst_str, ifname, fd, pim_msg_size,
495 e, safe_strerror(e));
498 zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
509 static int hello_send(struct interface *ifp,
512 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
513 struct pim_interface *pim_ifp;
519 if (PIM_DEBUG_PIM_HELLO) {
521 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str));
522 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",
526 pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec,
527 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
528 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
529 listcount(ifp->connected));
532 pim_tlv_size = pim_hello_build_tlv(ifp->name,
533 pim_msg + PIM_PIM_MIN_LEN,
534 sizeof(pim_msg) - PIM_PIM_MIN_LEN,
536 pim_ifp->pim_dr_priority,
537 pim_ifp->pim_generation_id,
538 pim_ifp->pim_propagation_delay_msec,
539 pim_ifp->pim_override_interval_msec,
540 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
542 if (pim_tlv_size < 0) {
546 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
548 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
549 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
551 pim_msg_build_header(pim_msg, pim_msg_size,
554 if (pim_msg_send(pim_ifp->pim_sock_fd,
555 qpim_all_pim_routers_addr,
559 if (PIM_DEBUG_PIM_HELLO) {
560 zlog_debug("%s: could not send PIM message on interface %s",
561 __PRETTY_FUNCTION__, ifp->name);
569 static int pim_hello_send(struct interface *ifp,
572 struct pim_interface *pim_ifp;
578 if (hello_send(ifp, holdtime)) {
579 ++pim_ifp->pim_ifstat_hello_sendfail;
581 if (PIM_DEBUG_PIM_HELLO) {
582 zlog_warn("Could not send PIM hello on interface %s",
588 ++pim_ifp->pim_ifstat_hello_sent;
593 static void hello_resched(struct interface *ifp)
595 struct pim_interface *pim_ifp;
601 if (PIM_DEBUG_PIM_HELLO) {
602 zlog_debug("Rescheduling %d sec hello on interface %s",
603 pim_ifp->pim_hello_period, ifp->name);
605 THREAD_OFF(pim_ifp->t_pim_hello_timer);
606 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
608 ifp, pim_ifp->pim_hello_period);
614 static int on_pim_hello_send(struct thread *t)
616 struct pim_interface *pim_ifp;
617 struct interface *ifp;
626 * Schedule next hello
628 pim_ifp->t_pim_hello_timer = 0;
634 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
638 RFC 4601: 4.3.1. Sending Hello Messages
640 Thus, if a router needs to send a Join/Prune or Assert message on an
641 interface on which it has not yet sent a Hello message with the
642 currently configured IP address, then it MUST immediately send the
643 relevant Hello message without waiting for the Hello Timer to
644 expire, followed by the Join/Prune or Assert message.
646 void pim_hello_restart_now(struct interface *ifp)
648 struct pim_interface *pim_ifp;
655 * Reset next hello timer
660 * Immediately send hello
662 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
666 RFC 4601: 4.3.1. Sending Hello Messages
668 To allow new or rebooting routers to learn of PIM neighbors quickly,
669 when a Hello message is received from a new neighbor, or a Hello
670 message with a new GenID is received from an existing neighbor, a
671 new Hello message should be sent on this interface after a
672 randomized delay between 0 and Triggered_Hello_Delay.
674 void pim_hello_restart_triggered(struct interface *ifp)
676 struct pim_interface *pim_ifp;
677 int triggered_hello_delay_msec;
684 triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
686 if (pim_ifp->t_pim_hello_timer) {
687 long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
688 if (remain_msec <= triggered_hello_delay_msec) {
689 /* Rescheduling hello would increase the delay, then it's faster
690 to just wait for the scheduled periodic hello. */
694 THREAD_OFF(pim_ifp->t_pim_hello_timer);
695 pim_ifp->t_pim_hello_timer = 0;
697 zassert(!pim_ifp->t_pim_hello_timer);
699 random_msec = random() % (triggered_hello_delay_msec + 1);
701 if (PIM_DEBUG_PIM_HELLO) {
702 zlog_debug("Scheduling %d msec triggered hello on interface %s",
703 random_msec, ifp->name);
706 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
711 int pim_sock_add(struct interface *ifp)
713 struct pim_interface *pim_ifp;
714 struct in_addr ifaddr;
720 if (pim_ifp->pim_sock_fd >= 0) {
721 zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
722 pim_ifp->pim_sock_fd, ifp->name);
726 ifaddr = pim_ifp->primary_address;
728 pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
729 if (pim_ifp->pim_sock_fd < 0) {
730 zlog_warn("Could not open PIM socket on interface %s",
735 pim_ifp->t_pim_sock_read = 0;
736 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
739 * Just ensure that the new generation id
740 * actually chooses something different.
741 * Actually ran across a case where this
742 * happened, pre-switch to random().
743 * While this is unlikely to happen now
744 * let's make sure it doesn't.
746 old_genid = pim_ifp->pim_generation_id;
748 while (old_genid == pim_ifp->pim_generation_id)
749 pim_ifp->pim_generation_id = random();
751 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
752 ifp->name, ifp->ifindex);
755 * Start receiving PIM messages
757 pim_sock_read_on(ifp);
760 * Start sending PIM hello's
762 pim_hello_restart_triggered(ifp);