]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_pim.c
*: use an ifindex_t type, defined in lib/if.h, for ifindex values
[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 int e = errno;
499 char dst_str[100];
500 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
501 if (sent < 0) {
502 zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
503 __PRETTY_FUNCTION__,
504 dst_str, ifname, fd, pim_msg_size,
505 e, safe_strerror(e));
506 }
507 else {
508 zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
509 __PRETTY_FUNCTION__,
510 dst_str, ifname, fd,
511 pim_msg_size, sent);
512 }
513 return -1;
514 }
515
516 return 0;
517 }
518
519 static int hello_send(struct interface *ifp,
520 uint16_t holdtime)
521 {
522 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
523 struct pim_interface *pim_ifp;
524 int pim_tlv_size;
525 int pim_msg_size;
526
527 pim_ifp = ifp->info;
528
529 if (PIM_DEBUG_PIM_HELLO) {
530 char dst_str[100];
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",
533 __PRETTY_FUNCTION__,
534 dst_str, ifp->name,
535 holdtime,
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));
540 }
541
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,
545 holdtime,
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),
551 ifp->connected);
552 if (pim_tlv_size < 0) {
553 return -1;
554 }
555
556 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
557
558 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
559 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
560
561 pim_msg_build_header(pim_msg, pim_msg_size,
562 PIM_MSG_TYPE_HELLO);
563
564 if (pim_msg_send(pim_ifp->pim_sock_fd,
565 qpim_all_pim_routers_addr,
566 pim_msg,
567 pim_msg_size,
568 ifp->name)) {
569 if (PIM_DEBUG_PIM_HELLO) {
570 zlog_debug("%s: could not send PIM message on interface %s",
571 __PRETTY_FUNCTION__, ifp->name);
572 }
573 return -2;
574 }
575
576 return 0;
577 }
578
579 static int pim_hello_send(struct interface *ifp,
580 uint16_t holdtime)
581 {
582 struct pim_interface *pim_ifp;
583
584 zassert(ifp);
585 pim_ifp = ifp->info;
586 zassert(pim_ifp);
587
588 if (if_is_loopback (ifp))
589 return 0;
590
591 if (hello_send(ifp, holdtime)) {
592 ++pim_ifp->pim_ifstat_hello_sendfail;
593
594 if (PIM_DEBUG_PIM_HELLO) {
595 zlog_warn("Could not send PIM hello on interface %s",
596 ifp->name);
597 }
598 return -1;
599 }
600
601 ++pim_ifp->pim_ifstat_hello_sent;
602
603 return 0;
604 }
605
606 static void hello_resched(struct interface *ifp)
607 {
608 struct pim_interface *pim_ifp;
609
610 zassert(ifp);
611 pim_ifp = ifp->info;
612 zassert(pim_ifp);
613
614 if (PIM_DEBUG_PIM_HELLO) {
615 zlog_debug("Rescheduling %d sec hello on interface %s",
616 pim_ifp->pim_hello_period, ifp->name);
617 }
618 THREAD_OFF(pim_ifp->t_pim_hello_timer);
619 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
620 on_pim_hello_send,
621 ifp, pim_ifp->pim_hello_period);
622 }
623
624 /*
625 Periodic hello timer
626 */
627 static int on_pim_hello_send(struct thread *t)
628 {
629 struct pim_interface *pim_ifp;
630 struct interface *ifp;
631
632 zassert(t);
633 ifp = THREAD_ARG(t);
634 zassert(ifp);
635
636 pim_ifp = ifp->info;
637
638 /*
639 * Schedule next hello
640 */
641 pim_ifp->t_pim_hello_timer = 0;
642 hello_resched(ifp);
643
644 /*
645 * Send hello
646 */
647 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
648 }
649
650 /*
651 RFC 4601: 4.3.1. Sending Hello Messages
652
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.
658 */
659 void pim_hello_restart_now(struct interface *ifp)
660 {
661 struct pim_interface *pim_ifp;
662
663 zassert(ifp);
664 pim_ifp = ifp->info;
665 zassert(pim_ifp);
666
667 /*
668 * Reset next hello timer
669 */
670 hello_resched(ifp);
671
672 /*
673 * Immediately send hello
674 */
675 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
676 }
677
678 /*
679 RFC 4601: 4.3.1. Sending Hello Messages
680
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.
686 */
687 void pim_hello_restart_triggered(struct interface *ifp)
688 {
689 struct pim_interface *pim_ifp;
690 int triggered_hello_delay_msec;
691 int random_msec;
692
693 zassert(ifp);
694 pim_ifp = ifp->info;
695 zassert(pim_ifp);
696
697 triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
698
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. */
704 return;
705 }
706
707 THREAD_OFF(pim_ifp->t_pim_hello_timer);
708 pim_ifp->t_pim_hello_timer = 0;
709 }
710 zassert(!pim_ifp->t_pim_hello_timer);
711
712 random_msec = random() % (triggered_hello_delay_msec + 1);
713
714 if (PIM_DEBUG_PIM_HELLO) {
715 zlog_debug("Scheduling %d msec triggered hello on interface %s",
716 random_msec, ifp->name);
717 }
718
719 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
720 on_pim_hello_send,
721 ifp, random_msec);
722 }
723
724 int pim_sock_add(struct interface *ifp)
725 {
726 struct pim_interface *pim_ifp;
727 struct in_addr ifaddr;
728 uint32_t old_genid;
729
730 pim_ifp = ifp->info;
731 zassert(pim_ifp);
732
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);
736 return -1;
737 }
738
739 ifaddr = pim_ifp->primary_address;
740
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",
744 ifp->name);
745 return -2;
746 }
747
748 pim_ifp->t_pim_sock_read = 0;
749 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
750
751 /*
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.
758 */
759 old_genid = pim_ifp->pim_generation_id;
760
761 while (old_genid == pim_ifp->pim_generation_id)
762 pim_ifp->pim_generation_id = random();
763
764 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
765 ifp->name, ifp->ifindex);
766
767 /*
768 * Start receiving PIM messages
769 */
770 pim_sock_read_on(ifp);
771
772 /*
773 * Start sending PIM hello's
774 */
775 pim_hello_restart_triggered(ifp);
776
777 return 0;
778 }