blob: 156081ca08484d4cf96244b31895223249f202d7 [file] [log] [blame]
Everton Marques871dbcf2009-08-11 15:43:05 -03001/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4
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.
9
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.
14
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,
18 MA 02110-1301 USA
19
20 $QuaggaId: $Format:%an, %ai, %h$ $
21*/
22
23#include <zebra.h>
24
25#include "log.h"
26#include "thread.h"
27#include "memory.h"
28
29#include "pimd.h"
30#include "pim_pim.h"
31#include "pim_time.h"
32#include "pim_iface.h"
33#include "pim_sock.h"
34#include "pim_str.h"
35#include "pim_util.h"
36#include "pim_tlv.h"
37#include "pim_neighbor.h"
38#include "pim_hello.h"
39#include "pim_join.h"
40#include "pim_assert.h"
41#include "pim_msg.h"
42#include "pim_rand.h"
43
44static int on_pim_hello_send(struct thread *t);
45static int pim_hello_send(struct interface *ifp,
46 uint16_t holdtime);
47
48static void sock_close(struct interface *ifp)
49{
50 struct pim_interface *pim_ifp = ifp->info;
51
52 if (PIM_DEBUG_PIM_TRACE) {
53 if (pim_ifp->t_pim_sock_read) {
54 zlog_debug("Cancelling READ event for PIM socket fd=%d on interface %s",
55 pim_ifp->pim_sock_fd,
56 ifp->name);
57 }
58 }
59 THREAD_OFF(pim_ifp->t_pim_sock_read);
60
61 if (PIM_DEBUG_PIM_TRACE) {
62 if (pim_ifp->t_pim_hello_timer) {
63 zlog_debug("Cancelling PIM hello timer for interface %s",
64 ifp->name);
65 }
66 }
67 THREAD_OFF(pim_ifp->t_pim_hello_timer);
68
69 if (PIM_DEBUG_PIM_TRACE) {
70 zlog_debug("Deleting PIM socket fd=%d on interface %s",
71 pim_ifp->pim_sock_fd, ifp->name);
72 }
73
74 if (close(pim_ifp->pim_sock_fd)) {
75 zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
76 pim_ifp->pim_sock_fd, ifp->name,
Everton Marquese96f0af2009-08-11 15:48:02 -030077 errno, safe_strerror(errno));
Everton Marques871dbcf2009-08-11 15:43:05 -030078 }
79
80 pim_ifp->pim_sock_fd = -1;
81 pim_ifp->pim_sock_creation = 0;
82
83 zassert(pim_ifp->pim_sock_fd < 0);
84 zassert(!pim_ifp->t_pim_sock_read);
85 zassert(!pim_ifp->t_pim_hello_timer);
86 zassert(!pim_ifp->pim_sock_creation);
87}
88
89void pim_sock_delete(struct interface *ifp, const char *delete_message)
90{
91 zlog_info("PIM INTERFACE DOWN: on interface %s: %s",
92 ifp->name, delete_message);
93
Everton Marquese96f0af2009-08-11 15:48:02 -030094 if (!ifp->info) {
95 zlog_err("%s: %s: but PIM not enabled on interface %s (!)",
96 __PRETTY_FUNCTION__, delete_message, ifp->name);
97 return;
98 }
99
Everton Marques871dbcf2009-08-11 15:43:05 -0300100 /*
101 RFC 4601: 4.3.1. Sending Hello Messages
102
103 Before an interface goes down or changes primary IP address, a Hello
104 message with a zero HoldTime should be sent immediately (with the
105 old IP address if the IP address changed).
106 */
107 pim_hello_send(ifp, 0 /* zero-sec holdtime */);
108
109 pim_neighbor_delete_all(ifp, delete_message);
110
111 sock_close(ifp);
112}
113
114int pim_pim_packet(struct interface *ifp, char *buf, size_t len)
115{
116 struct ip *ip_hdr;
117 size_t ip_hlen; /* ip header length in bytes */
118 char src_str[100];
119 char dst_str[100];
120 char *pim_msg;
121 int pim_msg_len;
122 uint8_t pim_version;
123 uint8_t pim_type;
124 uint16_t pim_checksum; /* received checksum */
125 uint16_t checksum; /* computed checksum */
126 struct pim_neighbor *neigh;
127
128 if (!ifp->info) {
129 zlog_warn("%s: PIM not enabled on interface %s",
130 __PRETTY_FUNCTION__, ifp->name);
131 return -1;
132 }
133
134 if (len < sizeof(*ip_hdr)) {
David Lamparter5c697982012-02-16 04:47:56 +0100135 zlog_warn("PIM packet size=%zu shorter than minimum=%zu",
Everton Marques871dbcf2009-08-11 15:43:05 -0300136 len, sizeof(*ip_hdr));
137 return -1;
138 }
139
140 ip_hdr = (struct ip *) buf;
141
142 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
143 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str, sizeof(dst_str));
144
145 ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
146
147 if (PIM_DEBUG_PIM_PACKETS) {
David Lamparter5c697982012-02-16 04:47:56 +0100148 zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d",
Everton Marques871dbcf2009-08-11 15:43:05 -0300149 src_str, dst_str, ifp->name, len, ip_hlen, ip_hdr->ip_p);
150 }
151
152 if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) {
153 zlog_warn("IP packet protocol=%d is not PIM=%d",
154 ip_hdr->ip_p, PIM_IP_PROTO_PIM);
155 return -1;
156 }
157
158 if (ip_hlen < PIM_IP_HEADER_MIN_LEN) {
David Lamparter5c697982012-02-16 04:47:56 +0100159 zlog_warn("IP packet header size=%zu shorter than minimum=%d",
Everton Marques871dbcf2009-08-11 15:43:05 -0300160 ip_hlen, PIM_IP_HEADER_MIN_LEN);
161 return -1;
162 }
163 if (ip_hlen > PIM_IP_HEADER_MAX_LEN) {
David Lamparter5c697982012-02-16 04:47:56 +0100164 zlog_warn("IP packet header size=%zu greater than maximum=%d",
Everton Marques871dbcf2009-08-11 15:43:05 -0300165 ip_hlen, PIM_IP_HEADER_MAX_LEN);
166 return -1;
167 }
168
169 pim_msg = buf + ip_hlen;
170 pim_msg_len = len - ip_hlen;
171
Everton Marques62738042009-11-18 10:44:13 -0200172 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
173 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
174 }
175
Everton Marques871dbcf2009-08-11 15:43:05 -0300176 if (pim_msg_len < PIM_PIM_MIN_LEN) {
177 zlog_warn("PIM message size=%d shorter than minimum=%d",
178 pim_msg_len, PIM_PIM_MIN_LEN);
179 return -1;
180 }
181
182 pim_version = PIM_MSG_HDR_GET_VERSION(pim_msg);
183 pim_type = PIM_MSG_HDR_GET_TYPE(pim_msg);
184
185 if (pim_version != PIM_PROTO_VERSION) {
186 zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d",
187 ifp->name, pim_version);
188 return -1;
189 }
190
191 /* save received checksum */
192 pim_checksum = PIM_MSG_HDR_GET_CHECKSUM(pim_msg);
193
194 /* for computing checksum */
195 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0;
196
197 checksum = pim_inet_checksum(pim_msg, pim_msg_len);
198 if (checksum != pim_checksum) {
199 zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
200 ifp->name, pim_checksum, checksum);
201 return -1;
202 }
203
204 if (PIM_DEBUG_PIM_PACKETS) {
205 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",
206 src_str, dst_str, ifp->name, ip_hdr->ip_ttl,
207 pim_version, pim_type, pim_msg_len, checksum);
208 }
209
210 if (pim_type == PIM_MSG_TYPE_HELLO) {
211 return pim_hello_recv(ifp,
212 ip_hdr->ip_src,
213 pim_msg + PIM_MSG_HEADER_LEN,
214 pim_msg_len - PIM_MSG_HEADER_LEN);
215 }
216
217 neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
218 if (!neigh) {
219 zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
220 __FILE__, __PRETTY_FUNCTION__,
221 pim_type, src_str, ifp->name);
222 return -1;
223 }
224
225 switch (pim_type) {
226 case PIM_MSG_TYPE_JOIN_PRUNE:
227 return pim_joinprune_recv(ifp, neigh,
228 ip_hdr->ip_src,
229 pim_msg + PIM_MSG_HEADER_LEN,
230 pim_msg_len - PIM_MSG_HEADER_LEN);
231 case PIM_MSG_TYPE_ASSERT:
232 return pim_assert_recv(ifp, neigh,
233 ip_hdr->ip_src,
234 pim_msg + PIM_MSG_HEADER_LEN,
235 pim_msg_len - PIM_MSG_HEADER_LEN);
236 default:
237 zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s",
238 __FILE__, __PRETTY_FUNCTION__,
239 pim_type, src_str, ifp->name);
240 }
241
242 return -1;
243}
244
245static void pim_sock_read_on(struct interface *ifp);
246
247static int pim_sock_read(struct thread *t)
248{
249 struct interface *ifp;
250 struct pim_interface *pim_ifp;
251 int fd;
252 struct sockaddr_in from;
253 struct sockaddr_in to;
254 socklen_t fromlen = sizeof(from);
255 socklen_t tolen = sizeof(to);
256 char buf[PIM_PIM_BUFSIZE_READ];
257 int len;
258 int ifindex = -1;
259 int result = -1; /* defaults to bad */
260
261 zassert(t);
262
263 ifp = THREAD_ARG(t);
264 zassert(ifp);
265
266 fd = THREAD_FD(t);
267
268 pim_ifp = ifp->info;
269 zassert(pim_ifp);
270
271 zassert(fd == pim_ifp->pim_sock_fd);
272
273 len = pim_socket_recvfromto(fd, buf, sizeof(buf),
274 &from, &fromlen,
275 &to, &tolen,
276 &ifindex);
277 if (len < 0) {
278 zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s",
Everton Marquese96f0af2009-08-11 15:48:02 -0300279 fd, errno, safe_strerror(errno));
Everton Marques871dbcf2009-08-11 15:43:05 -0300280 goto done;
281 }
282
283 if (PIM_DEBUG_PIM_PACKETS) {
284 char from_str[100];
285 char to_str[100];
286
287 if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str)))
288 sprintf(from_str, "<from?>");
289 if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str)))
290 sprintf(to_str, "<to?>");
291
292 zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)",
293 len, from_str, to_str, fd, ifindex, ifp->ifindex);
294 }
295
Everton Marques62738042009-11-18 10:44:13 -0200296 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
297 pim_pkt_dump(__PRETTY_FUNCTION__, buf, len);
298 }
299
Everton Marques871dbcf2009-08-11 15:43:05 -0300300#ifdef PIM_CHECK_RECV_IFINDEX_SANITY
301 /* ifindex sanity check */
302 if (ifindex != (int) ifp->ifindex) {
303 char from_str[100];
304 char to_str[100];
305 struct interface *recv_ifp;
306
307 if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
308 sprintf(from_str, "<from?>");
309 if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
310 sprintf(to_str, "<to?>");
311
312 recv_ifp = if_lookup_by_index(ifindex);
313 if (recv_ifp) {
314 zassert(ifindex == (int) recv_ifp->ifindex);
315 }
316
317#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
318 zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
319 from_str, to_str, fd,
320 ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
321 ifp->ifindex, ifp->name);
322#endif
323 goto done;
324 }
325#endif
326
327 if (pim_pim_packet(ifp, buf, len)) {
328 goto done;
329 }
330
331 result = 0; /* good */
332
333 done:
334 pim_sock_read_on(ifp);
335
336 if (result) {
337 ++pim_ifp->pim_ifstat_hello_recvfail;
338 }
339
340 return result;
341}
342
343static void pim_sock_read_on(struct interface *ifp)
344{
345 struct pim_interface *pim_ifp;
346
347 zassert(ifp);
348 zassert(ifp->info);
349
350 pim_ifp = ifp->info;
351
352 if (PIM_DEBUG_PIM_TRACE) {
353 zlog_debug("Scheduling READ event on PIM socket fd=%d",
354 pim_ifp->pim_sock_fd);
355 }
356 pim_ifp->t_pim_sock_read = 0;
357 zassert(!pim_ifp->t_pim_sock_read);
358 THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
359 pim_ifp->pim_sock_fd);
360}
361
362static int pim_sock_open(struct in_addr ifaddr, int ifindex)
363{
364 int fd;
365
366 fd = pim_socket_mcast(IPPROTO_PIM, ifaddr, 0 /* loop=false */);
367 if (fd < 0)
368 return -1;
369
370 if (pim_socket_join(fd, qpim_all_pim_routers_addr, ifaddr, ifindex)) {
371 return -2;
372 }
373
374 return fd;
375}
376
377void pim_ifstat_reset(struct interface *ifp)
378{
379 struct pim_interface *pim_ifp;
380
381 zassert(ifp);
382
383 pim_ifp = ifp->info;
384 if (!pim_ifp) {
385 return;
386 }
387
388 pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
389 pim_ifp->pim_ifstat_hello_sent = 0;
390 pim_ifp->pim_ifstat_hello_sendfail = 0;
391 pim_ifp->pim_ifstat_hello_recv = 0;
392 pim_ifp->pim_ifstat_hello_recvfail = 0;
393}
394
395void pim_sock_reset(struct interface *ifp)
396{
397 struct pim_interface *pim_ifp;
398
399 zassert(ifp);
400 zassert(ifp->info);
401
402 pim_ifp = ifp->info;
403
404 pim_ifp->primary_address = pim_find_primary_addr(ifp);
405
406 pim_ifp->pim_sock_fd = -1;
407 pim_ifp->pim_sock_creation = 0;
408 pim_ifp->t_pim_sock_read = 0;
409
410 pim_ifp->t_pim_hello_timer = 0;
411 pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
412 pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
413 pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
414 pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
415 pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
416 pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
417 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
418 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
419 }
420 else {
421 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
422 }
423
424 /* neighbors without lan_delay */
425 pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
426 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
427 pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
428
429 /* DR Election */
430 pim_ifp->pim_dr_election_last = 0; /* timestamp */
431 pim_ifp->pim_dr_election_count = 0;
432 pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */
433 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
434
435 pim_ifstat_reset(ifp);
436}
437
438int pim_msg_send(int fd,
439 struct in_addr dst,
440 char *pim_msg,
441 int pim_msg_size,
442 const char *ifname)
443{
444 ssize_t sent;
445 struct sockaddr_in to;
446 socklen_t tolen;
447
448 if (PIM_DEBUG_PIM_PACKETS) {
449 char dst_str[100];
450 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
451 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
452 __PRETTY_FUNCTION__,
453 dst_str, ifname, pim_msg_size,
454 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg));
455 }
456
457#if 0
458 memset(&to, 0, sizeof(to));
459#endif
460 to.sin_family = AF_INET;
461 to.sin_addr = dst;
462#if 0
463 to.sin_port = htons(0);
464#endif
465 tolen = sizeof(to);
466
Everton Marques62738042009-11-18 10:44:13 -0200467 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
468 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
469 }
470
Everton Marques871dbcf2009-08-11 15:43:05 -0300471 sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT, &to, tolen);
472 if (sent != (ssize_t) pim_msg_size) {
473 int e = errno;
474 char dst_str[100];
475 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
476 if (sent < 0) {
477 zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
478 __PRETTY_FUNCTION__,
479 dst_str, ifname, fd, pim_msg_size,
Everton Marquese96f0af2009-08-11 15:48:02 -0300480 e, safe_strerror(e));
Everton Marques871dbcf2009-08-11 15:43:05 -0300481 }
482 else {
David Lamparter5c697982012-02-16 04:47:56 +0100483 zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
Everton Marques871dbcf2009-08-11 15:43:05 -0300484 __PRETTY_FUNCTION__,
485 dst_str, ifname, fd,
486 pim_msg_size, sent);
487 }
488 return -1;
489 }
490
491 return 0;
492}
493
494static int hello_send(struct interface *ifp,
495 uint16_t holdtime)
496{
497 char pim_msg[PIM_PIM_BUFSIZE_WRITE];
498 struct pim_interface *pim_ifp;
499 int pim_tlv_size;
500 int pim_msg_size;
501
502 pim_ifp = ifp->info;
503
504 if (PIM_DEBUG_PIM_PACKETS) {
505 char dst_str[100];
506 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str));
507 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",
508 __PRETTY_FUNCTION__,
509 dst_str, ifp->name,
510 holdtime,
511 pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec,
512 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
513 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
514 listcount(ifp->connected));
515 }
516
517 pim_tlv_size = pim_hello_build_tlv(ifp->name,
518 pim_msg + PIM_PIM_MIN_LEN,
519 sizeof(pim_msg) - PIM_PIM_MIN_LEN,
520 holdtime,
521 pim_ifp->pim_dr_priority,
522 pim_ifp->pim_generation_id,
523 pim_ifp->pim_propagation_delay_msec,
524 pim_ifp->pim_override_interval_msec,
525 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
526 ifp->connected);
527 if (pim_tlv_size < 0) {
528 return -1;
529 }
530
531 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
532
533 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
534 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
535
536 pim_msg_build_header(pim_msg, pim_msg_size,
537 PIM_MSG_TYPE_HELLO);
538
539 if (pim_msg_send(pim_ifp->pim_sock_fd,
540 qpim_all_pim_routers_addr,
541 pim_msg,
542 pim_msg_size,
543 ifp->name)) {
544 zlog_warn("%s: could not send PIM message on interface %s",
545 __PRETTY_FUNCTION__, ifp->name);
546 return -2;
547 }
548
549 return 0;
550}
551
552static int pim_hello_send(struct interface *ifp,
553 uint16_t holdtime)
554{
555 struct pim_interface *pim_ifp;
556
557 zassert(ifp);
558 pim_ifp = ifp->info;
559 zassert(pim_ifp);
560
561 if (hello_send(ifp, holdtime)) {
562 ++pim_ifp->pim_ifstat_hello_sendfail;
563
564 zlog_warn("Could not send PIM hello on interface %s",
565 ifp->name);
566 return -1;
567 }
568
569 ++pim_ifp->pim_ifstat_hello_sent;
570
571 return 0;
572}
573
574static void hello_resched(struct interface *ifp)
575{
576 struct pim_interface *pim_ifp;
577
578 zassert(ifp);
579 pim_ifp = ifp->info;
580 zassert(pim_ifp);
581
582 if (PIM_DEBUG_PIM_TRACE) {
583 zlog_debug("Rescheduling %d sec hello on interface %s",
584 pim_ifp->pim_hello_period, ifp->name);
585 }
586 THREAD_OFF(pim_ifp->t_pim_hello_timer);
587 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
588 on_pim_hello_send,
589 ifp, pim_ifp->pim_hello_period);
590}
591
592/*
593 Periodic hello timer
594 */
595static int on_pim_hello_send(struct thread *t)
596{
597 struct pim_interface *pim_ifp;
598 struct interface *ifp;
599
600 zassert(t);
601 ifp = THREAD_ARG(t);
602 zassert(ifp);
603
604 pim_ifp = ifp->info;
605
606 /*
607 * Schedule next hello
608 */
609 pim_ifp->t_pim_hello_timer = 0;
610 hello_resched(ifp);
611
612 /*
613 * Send hello
614 */
615 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
616}
617
618/*
619 RFC 4601: 4.3.1. Sending Hello Messages
620
621 Thus, if a router needs to send a Join/Prune or Assert message on an
622 interface on which it has not yet sent a Hello message with the
623 currently configured IP address, then it MUST immediately send the
624 relevant Hello message without waiting for the Hello Timer to
625 expire, followed by the Join/Prune or Assert message.
626 */
627void pim_hello_restart_now(struct interface *ifp)
628{
629 struct pim_interface *pim_ifp;
630
631 zassert(ifp);
632 pim_ifp = ifp->info;
633 zassert(pim_ifp);
634
635 /*
636 * Reset next hello timer
637 */
638 hello_resched(ifp);
639
640 /*
641 * Immediately send hello
642 */
643 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
644}
645
646/*
647 RFC 4601: 4.3.1. Sending Hello Messages
648
649 To allow new or rebooting routers to learn of PIM neighbors quickly,
650 when a Hello message is received from a new neighbor, or a Hello
651 message with a new GenID is received from an existing neighbor, a
652 new Hello message should be sent on this interface after a
653 randomized delay between 0 and Triggered_Hello_Delay.
654 */
655void pim_hello_restart_triggered(struct interface *ifp)
656{
657 struct pim_interface *pim_ifp;
658 int triggered_hello_delay_msec;
659 int random_msec;
660
661 zassert(ifp);
662 pim_ifp = ifp->info;
663 zassert(pim_ifp);
664
665 triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
666
667 if (pim_ifp->t_pim_hello_timer) {
668 long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
669 if (remain_msec <= triggered_hello_delay_msec) {
670 /* Rescheduling hello would increase the delay, then it's faster
671 to just wait for the scheduled periodic hello. */
672 return;
673 }
674
675 THREAD_OFF(pim_ifp->t_pim_hello_timer);
676 pim_ifp->t_pim_hello_timer = 0;
677 }
678 zassert(!pim_ifp->t_pim_hello_timer);
679
680 random_msec = pim_rand_next(0, triggered_hello_delay_msec);
681
682 if (PIM_DEBUG_PIM_EVENTS) {
683 zlog_debug("Scheduling %d msec triggered hello on interface %s",
684 random_msec, ifp->name);
685 }
686
687 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
688 on_pim_hello_send,
Leonard Herve236b0152009-08-11 15:51:52 -0300689 ifp, random_msec);
Everton Marques871dbcf2009-08-11 15:43:05 -0300690}
691
692int pim_sock_add(struct interface *ifp)
693{
694 struct pim_interface *pim_ifp;
695 struct in_addr ifaddr;
696
697 pim_ifp = ifp->info;
698 zassert(pim_ifp);
699
700 if (pim_ifp->pim_sock_fd >= 0) {
701 zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
702 pim_ifp->pim_sock_fd, ifp->name);
703 return -1;
704 }
705
706 ifaddr = pim_ifp->primary_address;
707
708 pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
709 if (pim_ifp->pim_sock_fd < 0) {
710 zlog_warn("Could not open PIM socket on interface %s",
711 ifp->name);
712 return -2;
713 }
714
715 pim_ifp->t_pim_sock_read = 0;
716 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
717
718 pim_ifp->pim_generation_id = pim_rand() & (int64_t) 0xFFFFFFFF;
719
720 zlog_info("PIM INTERFACE UP: on interface %s",
721 ifp->name);
722
723 /*
724 * Start receiving PIM messages
725 */
726 pim_sock_read_on(ifp);
727
728 /*
729 * Start sending PIM hello's
730 */
731 pim_hello_restart_triggered(ifp);
732
733 return 0;
734}