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