]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_pim.c
ospf6d: fix decimal area ID cli
[mirror_frr.git] / pimd / pim_pim.c
CommitLineData
12e41d03
DL
1/*
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
12e41d03
DL
19*/
20
21#include <zebra.h>
22
23#include "log.h"
24#include "thread.h"
25#include "memory.h"
744d91b3 26#include "if.h"
12e41d03
DL
27
28#include "pimd.h"
29#include "pim_pim.h"
30#include "pim_time.h"
31#include "pim_iface.h"
32#include "pim_sock.h"
33#include "pim_str.h"
34#include "pim_util.h"
35#include "pim_tlv.h"
36#include "pim_neighbor.h"
37#include "pim_hello.h"
38#include "pim_join.h"
39#include "pim_assert.h"
40#include "pim_msg.h"
77e390e5 41#include "pim_register.h"
12e41d03
DL
42
43static int on_pim_hello_send(struct thread *t);
44static int pim_hello_send(struct interface *ifp,
45 uint16_t holdtime);
46
47static void sock_close(struct interface *ifp)
48{
49 struct pim_interface *pim_ifp = ifp->info;
50
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",
54 pim_ifp->pim_sock_fd,
55 ifp->name);
56 }
57 }
58 THREAD_OFF(pim_ifp->t_pim_sock_read);
59
60 if (PIM_DEBUG_PIM_TRACE) {
61 if (pim_ifp->t_pim_hello_timer) {
62 zlog_debug("Cancelling PIM hello timer for interface %s",
63 ifp->name);
64 }
65 }
66 THREAD_OFF(pim_ifp->t_pim_hello_timer);
67
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);
71 }
72
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));
77 }
78
79 pim_ifp->pim_sock_fd = -1;
80 pim_ifp->pim_sock_creation = 0;
81
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);
86}
87
88void pim_sock_delete(struct interface *ifp, const char *delete_message)
89{
90 zlog_info("PIM INTERFACE DOWN: on interface %s: %s",
91 ifp->name, delete_message);
92
93 if (!ifp->info) {
94 zlog_err("%s: %s: but PIM not enabled on interface %s (!)",
95 __PRETTY_FUNCTION__, delete_message, ifp->name);
96 return;
97 }
98
99 /*
100 RFC 4601: 4.3.1. Sending Hello Messages
101
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).
105 */
106 pim_hello_send(ifp, 0 /* zero-sec holdtime */);
107
108 pim_neighbor_delete_all(ifp, delete_message);
109
110 sock_close(ifp);
111}
112
113int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
114{
115 struct ip *ip_hdr;
116 size_t ip_hlen; /* ip header length in bytes */
117 char src_str[100];
118 char dst_str[100];
119 uint8_t *pim_msg;
120 int pim_msg_len;
121 uint8_t pim_version;
122 uint8_t pim_type;
123 uint16_t pim_checksum; /* received checksum */
124 uint16_t checksum; /* computed checksum */
125 struct pim_neighbor *neigh;
126
127 if (!ifp->info) {
128 zlog_warn("%s: PIM not enabled on interface %s",
129 __PRETTY_FUNCTION__, ifp->name);
130 return -1;
131 }
132
133 if (len < sizeof(*ip_hdr)) {
134 zlog_warn("PIM packet size=%zu shorter than minimum=%zu",
135 len, sizeof(*ip_hdr));
136 return -1;
137 }
138
139 ip_hdr = (struct ip *) buf;
140
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));
143
144 ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
145
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);
149 }
150
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);
154 return -1;
155 }
156
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);
160 return -1;
161 }
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);
165 return -1;
166 }
167
168 pim_msg = buf + ip_hlen;
169 pim_msg_len = len - ip_hlen;
170
171 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
172 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
173 }
174
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);
178 return -1;
179 }
180
181 pim_version = PIM_MSG_HDR_GET_VERSION(pim_msg);
182 pim_type = PIM_MSG_HDR_GET_TYPE(pim_msg);
183
184 if (pim_version != PIM_PROTO_VERSION) {
185 zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d",
186 ifp->name, pim_version);
187 return -1;
188 }
189
190 /* save received checksum */
191 pim_checksum = PIM_MSG_HDR_GET_CHECKSUM(pim_msg);
192
193 /* for computing checksum */
194 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0;
195
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);
200 return -1;
201 }
202
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);
207 }
208
77e390e5 209 if (pim_type == PIM_MSG_TYPE_REG_STOP ||
566b83cf
DS
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)
214 {
215 if (PIM_DEBUG_PIM_PACKETS) {
216 zlog_debug("Recv PIM packet type %d which is not currently understood",
217 pim_type);
218 }
219 return -1;
220 }
221
12e41d03 222 if (pim_type == PIM_MSG_TYPE_HELLO) {
77e390e5
DS
223 return pim_hello_recv(ifp,
224 ip_hdr->ip_src,
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,
229 ip_hdr->ip_dst,
230 ip_hdr->ip_src,
231 pim_msg + PIM_MSG_HEADER_LEN,
232 pim_msg_len - PIM_MSG_HEADER_LEN);
12e41d03
DL
233 }
234
235 neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
236 if (!neigh) {
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);
240 return -1;
241 }
242
243 switch (pim_type) {
244 case PIM_MSG_TYPE_JOIN_PRUNE:
245 return pim_joinprune_recv(ifp, neigh,
246 ip_hdr->ip_src,
247 pim_msg + PIM_MSG_HEADER_LEN,
248 pim_msg_len - PIM_MSG_HEADER_LEN);
77e390e5 249 break;
12e41d03
DL
250 case PIM_MSG_TYPE_ASSERT:
251 return pim_assert_recv(ifp, neigh,
252 ip_hdr->ip_src,
253 pim_msg + PIM_MSG_HEADER_LEN,
254 pim_msg_len - PIM_MSG_HEADER_LEN);
77e390e5 255 break;
12e41d03
DL
256 default:
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);
77e390e5 260 break;
12e41d03
DL
261 }
262
263 return -1;
264}
265
266static void pim_sock_read_on(struct interface *ifp);
267
268static int pim_sock_read(struct thread *t)
269{
270 struct interface *ifp;
271 struct pim_interface *pim_ifp;
272 int fd;
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];
278 int len;
b892f1dd 279 ifindex_t ifindex = -1;
12e41d03
DL
280 int result = -1; /* defaults to bad */
281
282 zassert(t);
283
284 ifp = THREAD_ARG(t);
285 zassert(ifp);
286
287 fd = THREAD_FD(t);
288
289 pim_ifp = ifp->info;
290 zassert(pim_ifp);
291
292 zassert(fd == pim_ifp->pim_sock_fd);
293
294 len = pim_socket_recvfromto(fd, buf, sizeof(buf),
295 &from, &fromlen,
296 &to, &tolen,
297 &ifindex);
298 if (len < 0) {
299 zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s",
300 fd, errno, safe_strerror(errno));
301 goto done;
302 }
303
304 if (PIM_DEBUG_PIM_PACKETS) {
305 char from_str[100];
306 char to_str[100];
307
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?>");
312
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);
315 }
316
317 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
318 pim_pkt_dump(__PRETTY_FUNCTION__, buf, len);
319 }
320
321#ifdef PIM_CHECK_RECV_IFINDEX_SANITY
322 /* ifindex sanity check */
323 if (ifindex != (int) ifp->ifindex) {
324 char from_str[100];
325 char to_str[100];
326 struct interface *recv_ifp;
327
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?>");
332
333 recv_ifp = if_lookup_by_index(ifindex);
334 if (recv_ifp) {
335 zassert(ifindex == (int) recv_ifp->ifindex);
336 }
337
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);
343#endif
344 goto done;
345 }
346#endif
347
348 int fail = pim_pim_packet(ifp, buf, len);
349 if (fail) {
a22e470b
DS
350 if (PIM_DEBUG_PIM_PACKETS)
351 zlog_debug("%s: pim_pim_packet() return=%d",
352 __PRETTY_FUNCTION__, fail);
12e41d03
DL
353 goto done;
354 }
355
356 result = 0; /* good */
357
358 done:
359 pim_sock_read_on(ifp);
360
361 if (result) {
362 ++pim_ifp->pim_ifstat_hello_recvfail;
363 }
364
365 return result;
366}
367
368static void pim_sock_read_on(struct interface *ifp)
369{
370 struct pim_interface *pim_ifp;
371
372 zassert(ifp);
373 zassert(ifp->info);
374
375 pim_ifp = ifp->info;
376
3010e99a 377 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
12e41d03
DL
378 zlog_debug("Scheduling READ event on PIM socket fd=%d",
379 pim_ifp->pim_sock_fd);
380 }
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);
385}
386
b892f1dd 387static int pim_sock_open(struct in_addr ifaddr, ifindex_t ifindex)
12e41d03
DL
388{
389 int fd;
390
61ea3951 391 fd = pim_socket_mcast(IPPROTO_PIM, ifaddr, ifindex, 0 /* loop=false */);
12e41d03
DL
392 if (fd < 0)
393 return -1;
394
395 if (pim_socket_join(fd, qpim_all_pim_routers_addr, ifaddr, ifindex)) {
2cd32c61 396 close(fd);
12e41d03
DL
397 return -2;
398 }
399
400 return fd;
401}
402
403void pim_ifstat_reset(struct interface *ifp)
404{
405 struct pim_interface *pim_ifp;
406
407 zassert(ifp);
408
409 pim_ifp = ifp->info;
410 if (!pim_ifp) {
411 return;
412 }
413
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;
419}
420
421void pim_sock_reset(struct interface *ifp)
422{
423 struct pim_interface *pim_ifp;
424
425 zassert(ifp);
426 zassert(ifp->info);
427
428 pim_ifp = ifp->info;
429
430 pim_ifp->primary_address = pim_find_primary_addr(ifp);
431
432 pim_ifp->pim_sock_fd = -1;
433 pim_ifp->pim_sock_creation = 0;
434 pim_ifp->t_pim_sock_read = 0;
435
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);
445 }
446 else {
447 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
448 }
449
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;
454
455 /* DR Election */
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;
461
462 pim_ifstat_reset(ifp);
463}
464
465int pim_msg_send(int fd,
466 struct in_addr dst,
467 uint8_t *pim_msg,
468 int pim_msg_size,
469 const char *ifname)
470{
471 ssize_t sent;
472 struct sockaddr_in to;
473 socklen_t tolen;
474
475 if (PIM_DEBUG_PIM_PACKETS) {
476 char dst_str[100];
477 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
478 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
479 __PRETTY_FUNCTION__,
480 dst_str, ifname, pim_msg_size,
481 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg));
482 }
483
12e41d03 484 memset(&to, 0, sizeof(to));
12e41d03
DL
485 to.sin_family = AF_INET;
486 to.sin_addr = dst;
12e41d03
DL
487 tolen = sizeof(to);
488
489 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
490 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
491 }
492
59e96cda
DL
493 sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT,
494 (struct sockaddr *)&to, tolen);
12e41d03
DL
495 if (sent != (ssize_t) pim_msg_size) {
496 int e = errno;
497 char dst_str[100];
498 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
499 if (sent < 0) {
500 zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
501 __PRETTY_FUNCTION__,
502 dst_str, ifname, fd, pim_msg_size,
503 e, safe_strerror(e));
504 }
505 else {
506 zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
507 __PRETTY_FUNCTION__,
508 dst_str, ifname, fd,
509 pim_msg_size, sent);
510 }
511 return -1;
512 }
513
514 return 0;
515}
516
517static int hello_send(struct interface *ifp,
518 uint16_t holdtime)
519{
520 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
521 struct pim_interface *pim_ifp;
522 int pim_tlv_size;
523 int pim_msg_size;
524
525 pim_ifp = ifp->info;
526
aea6cb94 527 if (PIM_DEBUG_PIM_HELLO) {
12e41d03
DL
528 char dst_str[100];
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",
531 __PRETTY_FUNCTION__,
532 dst_str, ifp->name,
533 holdtime,
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));
538 }
539
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,
543 holdtime,
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),
549 ifp->connected);
550 if (pim_tlv_size < 0) {
551 return -1;
552 }
553
554 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
555
556 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
557 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
558
559 pim_msg_build_header(pim_msg, pim_msg_size,
560 PIM_MSG_TYPE_HELLO);
561
562 if (pim_msg_send(pim_ifp->pim_sock_fd,
563 qpim_all_pim_routers_addr,
564 pim_msg,
565 pim_msg_size,
566 ifp->name)) {
aea6cb94
DS
567 if (PIM_DEBUG_PIM_HELLO) {
568 zlog_debug("%s: could not send PIM message on interface %s",
569 __PRETTY_FUNCTION__, ifp->name);
570 }
12e41d03
DL
571 return -2;
572 }
573
574 return 0;
575}
576
577static int pim_hello_send(struct interface *ifp,
578 uint16_t holdtime)
579{
580 struct pim_interface *pim_ifp;
581
582 zassert(ifp);
583 pim_ifp = ifp->info;
584 zassert(pim_ifp);
585
85b62aea
DS
586 if (if_is_loopback (ifp))
587 return 0;
588
12e41d03
DL
589 if (hello_send(ifp, holdtime)) {
590 ++pim_ifp->pim_ifstat_hello_sendfail;
591
aea6cb94
DS
592 if (PIM_DEBUG_PIM_HELLO) {
593 zlog_warn("Could not send PIM hello on interface %s",
594 ifp->name);
595 }
12e41d03
DL
596 return -1;
597 }
598
599 ++pim_ifp->pim_ifstat_hello_sent;
600
601 return 0;
602}
603
604static void hello_resched(struct interface *ifp)
605{
606 struct pim_interface *pim_ifp;
607
608 zassert(ifp);
609 pim_ifp = ifp->info;
610 zassert(pim_ifp);
611
aea6cb94 612 if (PIM_DEBUG_PIM_HELLO) {
12e41d03
DL
613 zlog_debug("Rescheduling %d sec hello on interface %s",
614 pim_ifp->pim_hello_period, ifp->name);
615 }
616 THREAD_OFF(pim_ifp->t_pim_hello_timer);
617 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
618 on_pim_hello_send,
619 ifp, pim_ifp->pim_hello_period);
620}
621
622/*
623 Periodic hello timer
624 */
625static int on_pim_hello_send(struct thread *t)
626{
627 struct pim_interface *pim_ifp;
628 struct interface *ifp;
629
630 zassert(t);
631 ifp = THREAD_ARG(t);
632 zassert(ifp);
633
634 pim_ifp = ifp->info;
635
636 /*
637 * Schedule next hello
638 */
639 pim_ifp->t_pim_hello_timer = 0;
640 hello_resched(ifp);
641
642 /*
643 * Send hello
644 */
645 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
646}
647
648/*
649 RFC 4601: 4.3.1. Sending Hello Messages
650
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.
656 */
657void pim_hello_restart_now(struct interface *ifp)
658{
659 struct pim_interface *pim_ifp;
660
661 zassert(ifp);
662 pim_ifp = ifp->info;
663 zassert(pim_ifp);
664
665 /*
666 * Reset next hello timer
667 */
668 hello_resched(ifp);
669
670 /*
671 * Immediately send hello
672 */
673 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
674}
675
676/*
677 RFC 4601: 4.3.1. Sending Hello Messages
678
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.
684 */
685void pim_hello_restart_triggered(struct interface *ifp)
686{
687 struct pim_interface *pim_ifp;
688 int triggered_hello_delay_msec;
689 int random_msec;
690
691 zassert(ifp);
692 pim_ifp = ifp->info;
693 zassert(pim_ifp);
694
695 triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
696
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. */
702 return;
703 }
704
705 THREAD_OFF(pim_ifp->t_pim_hello_timer);
706 pim_ifp->t_pim_hello_timer = 0;
707 }
708 zassert(!pim_ifp->t_pim_hello_timer);
709
60b40924 710 random_msec = random() % (triggered_hello_delay_msec + 1);
12e41d03 711
aea6cb94 712 if (PIM_DEBUG_PIM_HELLO) {
12e41d03
DL
713 zlog_debug("Scheduling %d msec triggered hello on interface %s",
714 random_msec, ifp->name);
715 }
716
717 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
718 on_pim_hello_send,
719 ifp, random_msec);
720}
721
722int pim_sock_add(struct interface *ifp)
723{
724 struct pim_interface *pim_ifp;
725 struct in_addr ifaddr;
c29c0f61 726 uint32_t old_genid;
12e41d03
DL
727
728 pim_ifp = ifp->info;
729 zassert(pim_ifp);
730
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);
734 return -1;
735 }
736
737 ifaddr = pim_ifp->primary_address;
738
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",
742 ifp->name);
743 return -2;
744 }
745
746 pim_ifp->t_pim_sock_read = 0;
747 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
748
c29c0f61
DS
749 /*
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.
756 */
757 old_genid = pim_ifp->pim_generation_id;
758
759 while (old_genid == pim_ifp->pim_generation_id)
760 pim_ifp->pim_generation_id = random();
12e41d03
DL
761
762 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
763 ifp->name, ifp->ifindex);
764
765 /*
766 * Start receiving PIM messages
767 */
768 pim_sock_read_on(ifp);
769
770 /*
771 * Start sending PIM hello's
772 */
773 pim_hello_restart_triggered(ifp);
774
775 return 0;
776}