]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_pim.c
Merge pull request #254 from donaldsharp/shutdown3
[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
21 #include <zebra.h>
22
23 #include "log.h"
24 #include "thread.h"
25 #include "memory.h"
26 #include "if.h"
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"
41 #include "pim_register.h"
42
43 static int on_pim_hello_send(struct thread *t);
44 static int pim_hello_send(struct interface *ifp,
45 uint16_t holdtime);
46
47 static
48 const char *pim_pim_msgtype2str (enum pim_msg_type type)
49 {
50 switch (type)
51 {
52 case PIM_MSG_TYPE_HELLO: return "HELLO";
53 case PIM_MSG_TYPE_REGISTER: return "REGISTER";
54 case PIM_MSG_TYPE_REG_STOP: return "REGSTOP";
55 case PIM_MSG_TYPE_JOIN_PRUNE: return "JOINPRUNE";
56 case PIM_MSG_TYPE_BOOTSTRAP: return "BOOT";
57 case PIM_MSG_TYPE_ASSERT: return "ASSERT";
58 case PIM_MSG_TYPE_GRAFT: return "GRAFT";
59 case PIM_MSG_TYPE_GRAFT_ACK: return "GACK";
60 case PIM_MSG_TYPE_CANDIDATE: return "CANDIDATE";
61 }
62
63 return "UNKNOWN";
64 }
65
66 static void sock_close(struct interface *ifp)
67 {
68 struct pim_interface *pim_ifp = ifp->info;
69
70 if (PIM_DEBUG_PIM_TRACE) {
71 if (pim_ifp->t_pim_sock_read) {
72 zlog_debug("Cancelling READ event for PIM socket fd=%d on interface %s",
73 pim_ifp->pim_sock_fd,
74 ifp->name);
75 }
76 }
77 THREAD_OFF(pim_ifp->t_pim_sock_read);
78
79 if (PIM_DEBUG_PIM_TRACE) {
80 if (pim_ifp->t_pim_hello_timer) {
81 zlog_debug("Cancelling PIM hello timer for interface %s",
82 ifp->name);
83 }
84 }
85 THREAD_OFF(pim_ifp->t_pim_hello_timer);
86
87 if (PIM_DEBUG_PIM_TRACE) {
88 zlog_debug("Deleting PIM socket fd=%d on interface %s",
89 pim_ifp->pim_sock_fd, ifp->name);
90 }
91
92 /*
93 * If the fd is already deleted no need to do anything here
94 */
95 if (pim_ifp->pim_sock_fd > 0 && close(pim_ifp->pim_sock_fd)) {
96 zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
97 pim_ifp->pim_sock_fd, ifp->name,
98 errno, safe_strerror(errno));
99 }
100
101 pim_ifp->pim_sock_fd = -1;
102 pim_ifp->pim_sock_creation = 0;
103 }
104
105 void pim_sock_delete(struct interface *ifp, const char *delete_message)
106 {
107 zlog_info("PIM INTERFACE DOWN: on interface %s: %s",
108 ifp->name, delete_message);
109
110 if (!ifp->info) {
111 zlog_err("%s: %s: but PIM not enabled on interface %s (!)",
112 __PRETTY_FUNCTION__, delete_message, ifp->name);
113 return;
114 }
115
116 /*
117 RFC 4601: 4.3.1. Sending Hello Messages
118
119 Before an interface goes down or changes primary IP address, a Hello
120 message with a zero HoldTime should be sent immediately (with the
121 old IP address if the IP address changed).
122 */
123 pim_hello_send(ifp, 0 /* zero-sec holdtime */);
124
125 pim_neighbor_delete_all(ifp, delete_message);
126
127 sock_close(ifp);
128 }
129
130 int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
131 {
132 struct ip *ip_hdr;
133 size_t ip_hlen; /* ip header length in bytes */
134 char src_str[INET_ADDRSTRLEN];
135 char dst_str[INET_ADDRSTRLEN];
136 uint8_t *pim_msg;
137 int pim_msg_len;
138 uint16_t pim_checksum; /* received checksum */
139 uint16_t checksum; /* computed checksum */
140 struct pim_neighbor *neigh;
141 struct pim_msg_header *header;
142
143 if (len < sizeof(*ip_hdr)) {
144 if (PIM_DEBUG_PIM_PACKETS)
145 zlog_debug("PIM packet size=%zu shorter than minimum=%zu",
146 len, sizeof(*ip_hdr));
147 return -1;
148 }
149
150 ip_hdr = (struct ip *) buf;
151 ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
152
153 pim_msg = buf + ip_hlen;
154 pim_msg_len = len - ip_hlen;
155
156 header = (struct pim_msg_header *)pim_msg;
157 if (pim_msg_len < PIM_PIM_MIN_LEN) {
158 if (PIM_DEBUG_PIM_PACKETS)
159 zlog_debug("PIM message size=%d shorter than minimum=%d",
160 pim_msg_len, PIM_PIM_MIN_LEN);
161 return -1;
162 }
163
164 if (header->ver != PIM_PROTO_VERSION) {
165 if (PIM_DEBUG_PIM_PACKETS)
166 zlog_debug("Ignoring PIM pkt from %s with unsupported version: %d",
167 ifp->name, header->ver);
168 return -1;
169 }
170
171 /* save received checksum */
172 pim_checksum = header->checksum;
173
174 /* for computing checksum */
175 header->checksum = 0;
176
177 if (header->type == PIM_MSG_TYPE_REGISTER)
178 {
179 /* First 8 byte header checksum */
180 checksum = in_cksum (pim_msg, PIM_MSG_REGISTER_LEN);
181 if (checksum != pim_checksum)
182 {
183 checksum = in_cksum (pim_msg, pim_msg_len);
184 if (checksum != pim_checksum)
185 {
186 if (PIM_DEBUG_PIM_PACKETS)
187 zlog_debug
188 ("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
189 ifp->name, pim_checksum, checksum);
190
191 return -1;
192 }
193 }
194 }
195 else
196 {
197 checksum = in_cksum (pim_msg, pim_msg_len);
198 if (checksum != pim_checksum)
199 {
200 if (PIM_DEBUG_PIM_PACKETS)
201 zlog_debug
202 ("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
203 ifp->name, pim_checksum, checksum);
204
205 return -1;
206 }
207 }
208
209 if (PIM_DEBUG_PIM_PACKETS) {
210 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
211 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str, sizeof(dst_str));
212 zlog_debug("Recv PIM %s packet from %s to %s on %s: ttl=%d pim_version=%d pim_msg_size=%d checksum=%x",
213 pim_pim_msgtype2str (header->type), src_str, dst_str, ifp->name,
214 ip_hdr->ip_ttl, header->ver, pim_msg_len, checksum);
215 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
216 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
217 }
218 }
219
220 switch (header->type)
221 {
222 case PIM_MSG_TYPE_HELLO:
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 break;
228 case PIM_MSG_TYPE_REGISTER:
229 return pim_register_recv (ifp,
230 ip_hdr->ip_dst,
231 ip_hdr->ip_src,
232 pim_msg + PIM_MSG_HEADER_LEN,
233 pim_msg_len - PIM_MSG_HEADER_LEN);
234 break;
235 case PIM_MSG_TYPE_REG_STOP:
236 return pim_register_stop_recv (pim_msg + PIM_MSG_HEADER_LEN,
237 pim_msg_len - PIM_MSG_HEADER_LEN);
238 break;
239 case PIM_MSG_TYPE_JOIN_PRUNE:
240 neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
241 if (!neigh) {
242 if (PIM_DEBUG_PIM_PACKETS)
243 zlog_debug("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
244 __FILE__, __PRETTY_FUNCTION__,
245 header->type, src_str, ifp->name);
246 return -1;
247 }
248 pim_neighbor_timer_reset(neigh, neigh->holdtime);
249 return pim_joinprune_recv(ifp, neigh,
250 ip_hdr->ip_src,
251 pim_msg + PIM_MSG_HEADER_LEN,
252 pim_msg_len - PIM_MSG_HEADER_LEN);
253 break;
254 case PIM_MSG_TYPE_ASSERT:
255 neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
256 if (!neigh) {
257 if (PIM_DEBUG_PIM_PACKETS)
258 zlog_debug("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
259 __FILE__, __PRETTY_FUNCTION__,
260 header->type, src_str, ifp->name);
261 return -1;
262 }
263 pim_neighbor_timer_reset(neigh, neigh->holdtime);
264 return pim_assert_recv(ifp, neigh,
265 ip_hdr->ip_src,
266 pim_msg + PIM_MSG_HEADER_LEN,
267 pim_msg_len - PIM_MSG_HEADER_LEN);
268 break;
269 default:
270 if (PIM_DEBUG_PIM_PACKETS) {
271 zlog_debug("Recv PIM packet type %d which is not currently understood",
272 header->type);
273 }
274 return -1;
275 }
276 return -1;
277 }
278
279 static void pim_sock_read_on(struct interface *ifp);
280
281 static int pim_sock_read(struct thread *t)
282 {
283 struct interface *ifp;
284 struct pim_interface *pim_ifp;
285 int fd;
286 struct sockaddr_in from;
287 struct sockaddr_in to;
288 socklen_t fromlen = sizeof(from);
289 socklen_t tolen = sizeof(to);
290 uint8_t buf[PIM_PIM_BUFSIZE_READ];
291 int len;
292 ifindex_t ifindex = -1;
293 int result = -1; /* defaults to bad */
294 static long long count = 0;
295 int cont = 1;
296
297 ifp = THREAD_ARG(t);
298 fd = THREAD_FD(t);
299
300 pim_ifp = ifp->info;
301
302 while (cont)
303 {
304 len = pim_socket_recvfromto(fd, buf, sizeof(buf),
305 &from, &fromlen,
306 &to, &tolen,
307 &ifindex);
308 if (len < 0)
309 {
310 if (errno == EINTR)
311 continue;
312 if (errno == EWOULDBLOCK || errno == EAGAIN)
313 {
314 cont = 0;
315 break;
316 }
317 if (PIM_DEBUG_PIM_PACKETS)
318 zlog_debug ("Received errno: %d %s", errno, safe_strerror (errno));
319 goto done;
320 }
321
322 #ifdef PIM_CHECK_RECV_IFINDEX_SANITY
323 /* ifindex sanity check */
324 if (ifindex != (int) ifp->ifindex) {
325 char from_str[INET_ADDRSTRLEN];
326 char to_str[INET_ADDRSTRLEN];
327 struct interface *recv_ifp;
328
329 if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
330 sprintf(from_str, "<from?>");
331 if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
332 sprintf(to_str, "<to?>");
333
334 recv_ifp = if_lookup_by_index(ifindex);
335 if (recv_ifp) {
336 zassert(ifindex == (int) recv_ifp->ifindex);
337 }
338
339 #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
340 zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
341 from_str, to_str, fd,
342 ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
343 ifp->ifindex, ifp->name);
344 #endif
345 goto done;
346 }
347 #endif
348
349 int fail = pim_pim_packet(ifp, buf, len);
350 if (fail) {
351 if (PIM_DEBUG_PIM_PACKETS)
352 zlog_debug("%s: pim_pim_packet() return=%d",
353 __PRETTY_FUNCTION__, fail);
354 goto done;
355 }
356
357 count++;
358 if (count % qpim_packet_process == 0)
359 cont = 0;
360 }
361
362 result = 0; /* good */
363
364 done:
365 pim_sock_read_on(ifp);
366
367 if (result) {
368 ++pim_ifp->pim_ifstat_hello_recvfail;
369 }
370
371 return result;
372 }
373
374 static void pim_sock_read_on(struct interface *ifp)
375 {
376 struct pim_interface *pim_ifp;
377
378 zassert(ifp);
379 zassert(ifp->info);
380
381 pim_ifp = ifp->info;
382
383 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
384 zlog_debug("Scheduling READ event on PIM socket fd=%d",
385 pim_ifp->pim_sock_fd);
386 }
387 pim_ifp->t_pim_sock_read = NULL;
388 THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
389 pim_ifp->pim_sock_fd);
390 }
391
392 static int pim_sock_open(struct interface *ifp)
393 {
394 int fd;
395 struct pim_interface *pim_ifp = ifp->info;
396
397 fd = pim_socket_mcast(IPPROTO_PIM, pim_ifp->primary_address, ifp, 0 /* loop=false */);
398 if (fd < 0)
399 return -1;
400
401 if (pim_socket_join(fd, qpim_all_pim_routers_addr, pim_ifp->primary_address, ifp->ifindex)) {
402 close(fd);
403 return -2;
404 }
405
406 return fd;
407 }
408
409 void pim_ifstat_reset(struct interface *ifp)
410 {
411 struct pim_interface *pim_ifp;
412
413 zassert(ifp);
414
415 pim_ifp = ifp->info;
416 if (!pim_ifp) {
417 return;
418 }
419
420 pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
421 pim_ifp->pim_ifstat_hello_sent = 0;
422 pim_ifp->pim_ifstat_hello_sendfail = 0;
423 pim_ifp->pim_ifstat_hello_recv = 0;
424 pim_ifp->pim_ifstat_hello_recvfail = 0;
425 }
426
427 void pim_sock_reset(struct interface *ifp)
428 {
429 struct pim_interface *pim_ifp;
430
431 zassert(ifp);
432 zassert(ifp->info);
433
434 pim_ifp = ifp->info;
435
436 pim_ifp->primary_address = pim_find_primary_addr(ifp);
437
438 pim_ifp->pim_sock_fd = -1;
439 pim_ifp->pim_sock_creation = 0;
440 pim_ifp->t_pim_sock_read = NULL;
441
442 pim_ifp->t_pim_hello_timer = NULL;
443 pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
444 pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
445 pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
446 pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
447 pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
448 pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
449 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
450 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
451 }
452 else {
453 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
454 }
455
456 /* neighbors without lan_delay */
457 pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
458 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
459 pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
460
461 /* DR Election */
462 pim_ifp->pim_dr_election_last = 0; /* timestamp */
463 pim_ifp->pim_dr_election_count = 0;
464 pim_ifp->pim_dr_election_changes = 0;
465 pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */
466 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
467
468 pim_ifstat_reset(ifp);
469 }
470
471 static uint16_t ip_id = 0;
472
473
474 static int
475 pim_msg_send_frame (int fd, char *buf, size_t len,
476 struct sockaddr *dst, size_t salen)
477 {
478 struct ip *ip = (struct ip *)buf;
479
480 while (sendto (fd, buf, len, MSG_DONTWAIT, dst, salen) < 0)
481 {
482 char dst_str[INET_ADDRSTRLEN];
483
484 switch (errno)
485 {
486 case EMSGSIZE:
487 {
488 size_t hdrsize = sizeof (struct ip);
489 size_t newlen1 = ((len - hdrsize) / 2 ) & 0xFFF8;
490 size_t sendlen = newlen1 + hdrsize;
491 size_t offset = ntohs (ip->ip_off);
492
493 ip->ip_len = htons (sendlen);
494 ip->ip_off = htons (offset | IP_MF);
495 if (pim_msg_send_frame (fd, buf, sendlen, dst, salen) == 0)
496 {
497 struct ip *ip2 = (struct ip *)(buf + newlen1);
498 size_t newlen2 = len - sendlen;
499 sendlen = newlen2 + hdrsize;
500
501 memcpy (ip2, ip, hdrsize);
502 ip2->ip_len = htons (sendlen);
503 ip2->ip_off = htons (offset + (newlen1 >> 3));
504 return pim_msg_send_frame (fd, (char *)ip2, sendlen, dst, salen);
505 }
506 }
507
508 return -1;
509 break;
510 default:
511 if (PIM_DEBUG_PIM_PACKETS)
512 {
513 pim_inet4_dump ("<dst?>", ip->ip_dst, dst_str, sizeof (dst_str));
514 zlog_warn ("%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
515 __PRETTY_FUNCTION__,
516 dst_str, fd, len,
517 errno, safe_strerror(errno));
518 }
519 return -1;
520 break;
521 }
522 }
523
524 return 0;
525 }
526
527 int
528 pim_msg_send(int fd, struct in_addr src,
529 struct in_addr dst, uint8_t *pim_msg,
530 int pim_msg_size, const char *ifname)
531 {
532 struct sockaddr_in to;
533 socklen_t tolen;
534 unsigned char buffer[10000];
535 unsigned char *msg_start;
536 uint8_t ttl = MAXTTL;
537 struct pim_msg_header *header;
538 struct ip *ip;
539
540 memset (buffer, 0, 10000);
541 int sendlen = sizeof (struct ip) + pim_msg_size;
542
543 msg_start = buffer + sizeof (struct ip);
544 memcpy (msg_start, pim_msg, pim_msg_size);
545
546 header = (struct pim_msg_header *)pim_msg;
547 /*
548 * Omnios apparently doesn't have a #define for IP default
549 * ttl that is the same as all other platforms.
550 */
551 #ifndef IPDEFTTL
552 #define IPDEFTTL 64
553 #endif
554 /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
555 switch (header->type)
556 {
557 case PIM_MSG_TYPE_HELLO:
558 case PIM_MSG_TYPE_JOIN_PRUNE:
559 case PIM_MSG_TYPE_BOOTSTRAP:
560 case PIM_MSG_TYPE_ASSERT:
561 ttl = 1;
562 break;
563 case PIM_MSG_TYPE_REGISTER:
564 case PIM_MSG_TYPE_REG_STOP:
565 case PIM_MSG_TYPE_GRAFT:
566 case PIM_MSG_TYPE_GRAFT_ACK:
567 case PIM_MSG_TYPE_CANDIDATE:
568 ttl = IPDEFTTL;
569 break;
570 default:
571 ttl = MAXTTL;
572 break;
573 }
574
575 ip = (struct ip *) buffer;
576 ip->ip_id = htons (++ip_id);
577 ip->ip_hl = 5;
578 ip->ip_v = 4;
579 ip->ip_p = PIM_IP_PROTO_PIM;
580 ip->ip_src = src;
581 ip->ip_dst = dst;
582 ip->ip_ttl = ttl;
583 ip->ip_len = htons (sendlen);
584
585 if (PIM_DEBUG_PIM_PACKETS) {
586 struct pim_msg_header *header = (struct pim_msg_header *)pim_msg;
587 char dst_str[INET_ADDRSTRLEN];
588 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
589 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
590 __PRETTY_FUNCTION__,
591 dst_str, ifname, pim_msg_size,
592 header->checksum);
593 }
594
595 memset(&to, 0, sizeof(to));
596 to.sin_family = AF_INET;
597 to.sin_addr = dst;
598 tolen = sizeof(to);
599
600 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
601 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
602 }
603
604 pim_msg_send_frame (fd, (char *)buffer, sendlen,
605 (struct sockaddr *)&to, tolen);
606 return 0;
607 }
608
609 static int hello_send(struct interface *ifp,
610 uint16_t holdtime)
611 {
612 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
613 struct pim_interface *pim_ifp;
614 int pim_tlv_size;
615 int pim_msg_size;
616
617 pim_ifp = ifp->info;
618
619 if (PIM_DEBUG_PIM_HELLO) {
620 char dst_str[INET_ADDRSTRLEN];
621 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str));
622 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",
623 __PRETTY_FUNCTION__,
624 dst_str, ifp->name,
625 holdtime,
626 pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec,
627 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
628 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
629 listcount(ifp->connected));
630 }
631
632 pim_tlv_size = pim_hello_build_tlv(ifp->name,
633 pim_msg + PIM_PIM_MIN_LEN,
634 sizeof(pim_msg) - PIM_PIM_MIN_LEN,
635 holdtime,
636 pim_ifp->pim_dr_priority,
637 pim_ifp->pim_generation_id,
638 pim_ifp->pim_propagation_delay_msec,
639 pim_ifp->pim_override_interval_msec,
640 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
641 ifp->connected);
642 if (pim_tlv_size < 0) {
643 return -1;
644 }
645
646 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
647
648 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
649 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
650
651 pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO);
652
653 if (pim_msg_send(pim_ifp->pim_sock_fd,
654 pim_ifp->primary_address,
655 qpim_all_pim_routers_addr,
656 pim_msg,
657 pim_msg_size,
658 ifp->name)) {
659 if (PIM_DEBUG_PIM_HELLO) {
660 zlog_debug("%s: could not send PIM message on interface %s",
661 __PRETTY_FUNCTION__, ifp->name);
662 }
663 return -2;
664 }
665
666 return 0;
667 }
668
669 static int pim_hello_send(struct interface *ifp,
670 uint16_t holdtime)
671 {
672 struct pim_interface *pim_ifp;
673
674 zassert(ifp);
675 pim_ifp = ifp->info;
676 zassert(pim_ifp);
677
678 if (if_is_loopback (ifp))
679 return 0;
680
681 if (hello_send(ifp, holdtime)) {
682 ++pim_ifp->pim_ifstat_hello_sendfail;
683
684 if (PIM_DEBUG_PIM_HELLO) {
685 zlog_warn("Could not send PIM hello on interface %s",
686 ifp->name);
687 }
688 return -1;
689 }
690
691 ++pim_ifp->pim_ifstat_hello_sent;
692
693 return 0;
694 }
695
696 static void hello_resched(struct interface *ifp)
697 {
698 struct pim_interface *pim_ifp;
699
700 zassert(ifp);
701 pim_ifp = ifp->info;
702 zassert(pim_ifp);
703
704 if (PIM_DEBUG_PIM_HELLO) {
705 zlog_debug("Rescheduling %d sec hello on interface %s",
706 pim_ifp->pim_hello_period, ifp->name);
707 }
708 THREAD_OFF(pim_ifp->t_pim_hello_timer);
709 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
710 on_pim_hello_send,
711 ifp, pim_ifp->pim_hello_period);
712 }
713
714 /*
715 Periodic hello timer
716 */
717 static int on_pim_hello_send(struct thread *t)
718 {
719 struct pim_interface *pim_ifp;
720 struct interface *ifp;
721
722 ifp = THREAD_ARG(t);
723
724 pim_ifp = ifp->info;
725
726 /*
727 * Schedule next hello
728 */
729 pim_ifp->t_pim_hello_timer = NULL;
730 hello_resched(ifp);
731
732 /*
733 * Send hello
734 */
735 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
736 }
737
738 /*
739 RFC 4601: 4.3.1. Sending Hello Messages
740
741 Thus, if a router needs to send a Join/Prune or Assert message on an
742 interface on which it has not yet sent a Hello message with the
743 currently configured IP address, then it MUST immediately send the
744 relevant Hello message without waiting for the Hello Timer to
745 expire, followed by the Join/Prune or Assert message.
746 */
747 void pim_hello_restart_now(struct interface *ifp)
748 {
749 struct pim_interface *pim_ifp;
750
751 zassert(ifp);
752 pim_ifp = ifp->info;
753 zassert(pim_ifp);
754
755 /*
756 * Reset next hello timer
757 */
758 hello_resched(ifp);
759
760 /*
761 * Immediately send hello
762 */
763 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
764 }
765
766 /*
767 RFC 4601: 4.3.1. Sending Hello Messages
768
769 To allow new or rebooting routers to learn of PIM neighbors quickly,
770 when a Hello message is received from a new neighbor, or a Hello
771 message with a new GenID is received from an existing neighbor, a
772 new Hello message should be sent on this interface after a
773 randomized delay between 0 and Triggered_Hello_Delay.
774 */
775 void pim_hello_restart_triggered(struct interface *ifp)
776 {
777 struct pim_interface *pim_ifp;
778 int triggered_hello_delay_msec;
779 int random_msec;
780
781 zassert(ifp);
782 pim_ifp = ifp->info;
783 zassert(pim_ifp);
784
785 /*
786 * There exists situations where we have the a RPF out this
787 * interface, but we haven't formed a neighbor yet. This
788 * happens especially during interface flaps. While
789 * we would like to handle this more gracefully in other
790 * parts of the code. In order to get us up and running
791 * let's just send the hello immediate'ish
792 * This should be revisited when we get nexthop tracking
793 * in and when we have a better handle on safely
794 * handling the rpf information for upstreams that
795 * we cannot legally reach yet.
796 */
797 triggered_hello_delay_msec = 1;
798 //triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
799
800 if (pim_ifp->t_pim_hello_timer) {
801 long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
802 if (remain_msec <= triggered_hello_delay_msec) {
803 /* Rescheduling hello would increase the delay, then it's faster
804 to just wait for the scheduled periodic hello. */
805 return;
806 }
807
808 THREAD_OFF(pim_ifp->t_pim_hello_timer);
809 pim_ifp->t_pim_hello_timer = NULL;
810 }
811
812 random_msec = triggered_hello_delay_msec;
813 //random_msec = random() % (triggered_hello_delay_msec + 1);
814
815 if (PIM_DEBUG_PIM_HELLO) {
816 zlog_debug("Scheduling %d msec triggered hello on interface %s",
817 random_msec, ifp->name);
818 }
819
820 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
821 on_pim_hello_send,
822 ifp, random_msec);
823 }
824
825 int pim_sock_add(struct interface *ifp)
826 {
827 struct pim_interface *pim_ifp;
828 uint32_t old_genid;
829
830 pim_ifp = ifp->info;
831 zassert(pim_ifp);
832
833 if (pim_ifp->pim_sock_fd >= 0) {
834 if (PIM_DEBUG_PIM_PACKETS)
835 zlog_debug("Can't recreate existing PIM socket fd=%d for interface %s",
836 pim_ifp->pim_sock_fd, ifp->name);
837 return -1;
838 }
839
840 pim_ifp->pim_sock_fd = pim_sock_open(ifp);
841 if (pim_ifp->pim_sock_fd < 0) {
842 if (PIM_DEBUG_PIM_PACKETS)
843 zlog_debug("Could not open PIM socket on interface %s",
844 ifp->name);
845 return -2;
846 }
847
848 pim_socket_ip_hdr (pim_ifp->pim_sock_fd);
849
850 pim_ifp->t_pim_sock_read = NULL;
851 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
852
853 /*
854 * Just ensure that the new generation id
855 * actually chooses something different.
856 * Actually ran across a case where this
857 * happened, pre-switch to random().
858 * While this is unlikely to happen now
859 * let's make sure it doesn't.
860 */
861 old_genid = pim_ifp->pim_generation_id;
862
863 while (old_genid == pim_ifp->pim_generation_id)
864 pim_ifp->pim_generation_id = random();
865
866 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
867 ifp->name, ifp->ifindex);
868
869 /*
870 * Start receiving PIM messages
871 */
872 pim_sock_read_on(ifp);
873
874 /*
875 * Start sending PIM hello's
876 */
877 pim_hello_restart_triggered(ifp);
878
879 return 0;
880 }