]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_pim.c
Merge pull request #294 from opensourcerouting/modules
[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 break;
314
315 if (PIM_DEBUG_PIM_PACKETS)
316 zlog_debug ("Received errno: %d %s", errno, safe_strerror (errno));
317 goto done;
318 }
319
320 #ifdef PIM_CHECK_RECV_IFINDEX_SANITY
321 /* ifindex sanity check */
322 if (ifindex != (int) ifp->ifindex) {
323 char from_str[INET_ADDRSTRLEN];
324 char to_str[INET_ADDRSTRLEN];
325 struct interface *recv_ifp;
326
327 if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
328 sprintf(from_str, "<from?>");
329 if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
330 sprintf(to_str, "<to?>");
331
332 recv_ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
333 if (recv_ifp) {
334 zassert(ifindex == (int) recv_ifp->ifindex);
335 }
336
337 #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
338 zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
339 from_str, to_str, fd,
340 ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
341 ifp->ifindex, ifp->name);
342 #endif
343 goto done;
344 }
345 #endif
346
347 int fail = pim_pim_packet(ifp, buf, len);
348 if (fail) {
349 if (PIM_DEBUG_PIM_PACKETS)
350 zlog_debug("%s: pim_pim_packet() return=%d",
351 __PRETTY_FUNCTION__, fail);
352 goto done;
353 }
354
355 count++;
356 if (count % qpim_packet_process == 0)
357 cont = 0;
358 }
359
360 result = 0; /* good */
361
362 done:
363 pim_sock_read_on(ifp);
364
365 if (result) {
366 ++pim_ifp->pim_ifstat_hello_recvfail;
367 }
368
369 return result;
370 }
371
372 static void pim_sock_read_on(struct interface *ifp)
373 {
374 struct pim_interface *pim_ifp;
375
376 zassert(ifp);
377 zassert(ifp->info);
378
379 pim_ifp = ifp->info;
380
381 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
382 zlog_debug("Scheduling READ event on PIM socket fd=%d",
383 pim_ifp->pim_sock_fd);
384 }
385 pim_ifp->t_pim_sock_read = NULL;
386 THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
387 pim_ifp->pim_sock_fd);
388 }
389
390 static int pim_sock_open(struct interface *ifp)
391 {
392 int fd;
393 struct pim_interface *pim_ifp = ifp->info;
394
395 fd = pim_socket_mcast(IPPROTO_PIM, pim_ifp->primary_address, ifp, 0 /* loop=false */);
396 if (fd < 0)
397 return -1;
398
399 if (pim_socket_join(fd, qpim_all_pim_routers_addr, pim_ifp->primary_address, ifp->ifindex)) {
400 close(fd);
401 return -2;
402 }
403
404 return fd;
405 }
406
407 void pim_ifstat_reset(struct interface *ifp)
408 {
409 struct pim_interface *pim_ifp;
410
411 zassert(ifp);
412
413 pim_ifp = ifp->info;
414 if (!pim_ifp) {
415 return;
416 }
417
418 pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
419 pim_ifp->pim_ifstat_hello_sent = 0;
420 pim_ifp->pim_ifstat_hello_sendfail = 0;
421 pim_ifp->pim_ifstat_hello_recv = 0;
422 pim_ifp->pim_ifstat_hello_recvfail = 0;
423 }
424
425 void pim_sock_reset(struct interface *ifp)
426 {
427 struct pim_interface *pim_ifp;
428
429 zassert(ifp);
430 zassert(ifp->info);
431
432 pim_ifp = ifp->info;
433
434 pim_ifp->primary_address = pim_find_primary_addr(ifp);
435
436 pim_ifp->pim_sock_fd = -1;
437 pim_ifp->pim_sock_creation = 0;
438 pim_ifp->t_pim_sock_read = NULL;
439
440 pim_ifp->t_pim_hello_timer = NULL;
441 pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
442 pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
443 pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
444 pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
445 pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
446 pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
447 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
448 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
449 }
450 else {
451 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
452 }
453
454 /* neighbors without lan_delay */
455 pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
456 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
457 pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
458
459 /* DR Election */
460 pim_ifp->pim_dr_election_last = 0; /* timestamp */
461 pim_ifp->pim_dr_election_count = 0;
462 pim_ifp->pim_dr_election_changes = 0;
463 pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */
464 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
465
466 pim_ifstat_reset(ifp);
467 }
468
469 static uint16_t ip_id = 0;
470
471
472 static int
473 pim_msg_send_frame (int fd, char *buf, size_t len,
474 struct sockaddr *dst, size_t salen)
475 {
476 struct ip *ip = (struct ip *)buf;
477
478 while (sendto (fd, buf, len, MSG_DONTWAIT, dst, salen) < 0)
479 {
480 char dst_str[INET_ADDRSTRLEN];
481
482 switch (errno)
483 {
484 case EMSGSIZE:
485 {
486 size_t hdrsize = sizeof (struct ip);
487 size_t newlen1 = ((len - hdrsize) / 2 ) & 0xFFF8;
488 size_t sendlen = newlen1 + hdrsize;
489 size_t offset = ntohs (ip->ip_off);
490
491 ip->ip_len = htons (sendlen);
492 ip->ip_off = htons (offset | IP_MF);
493 if (pim_msg_send_frame (fd, buf, sendlen, dst, salen) == 0)
494 {
495 struct ip *ip2 = (struct ip *)(buf + newlen1);
496 size_t newlen2 = len - sendlen;
497 sendlen = newlen2 + hdrsize;
498
499 memcpy (ip2, ip, hdrsize);
500 ip2->ip_len = htons (sendlen);
501 ip2->ip_off = htons (offset + (newlen1 >> 3));
502 return pim_msg_send_frame (fd, (char *)ip2, sendlen, dst, salen);
503 }
504 }
505
506 return -1;
507 break;
508 default:
509 if (PIM_DEBUG_PIM_PACKETS)
510 {
511 pim_inet4_dump ("<dst?>", ip->ip_dst, dst_str, sizeof (dst_str));
512 zlog_warn ("%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
513 __PRETTY_FUNCTION__,
514 dst_str, fd, len,
515 errno, safe_strerror(errno));
516 }
517 return -1;
518 break;
519 }
520 }
521
522 return 0;
523 }
524
525 int
526 pim_msg_send(int fd, struct in_addr src,
527 struct in_addr dst, uint8_t *pim_msg,
528 int pim_msg_size, const char *ifname)
529 {
530 struct sockaddr_in to;
531 socklen_t tolen;
532 unsigned char buffer[10000];
533 unsigned char *msg_start;
534 uint8_t ttl = MAXTTL;
535 struct pim_msg_header *header;
536 struct ip *ip;
537
538 memset (buffer, 0, 10000);
539 int sendlen = sizeof (struct ip) + pim_msg_size;
540
541 msg_start = buffer + sizeof (struct ip);
542 memcpy (msg_start, pim_msg, pim_msg_size);
543
544 header = (struct pim_msg_header *)pim_msg;
545 /*
546 * Omnios apparently doesn't have a #define for IP default
547 * ttl that is the same as all other platforms.
548 */
549 #ifndef IPDEFTTL
550 #define IPDEFTTL 64
551 #endif
552 /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
553 switch (header->type)
554 {
555 case PIM_MSG_TYPE_HELLO:
556 case PIM_MSG_TYPE_JOIN_PRUNE:
557 case PIM_MSG_TYPE_BOOTSTRAP:
558 case PIM_MSG_TYPE_ASSERT:
559 ttl = 1;
560 break;
561 case PIM_MSG_TYPE_REGISTER:
562 case PIM_MSG_TYPE_REG_STOP:
563 case PIM_MSG_TYPE_GRAFT:
564 case PIM_MSG_TYPE_GRAFT_ACK:
565 case PIM_MSG_TYPE_CANDIDATE:
566 ttl = IPDEFTTL;
567 break;
568 default:
569 ttl = MAXTTL;
570 break;
571 }
572
573 ip = (struct ip *) buffer;
574 ip->ip_id = htons (++ip_id);
575 ip->ip_hl = 5;
576 ip->ip_v = 4;
577 ip->ip_p = PIM_IP_PROTO_PIM;
578 ip->ip_src = src;
579 ip->ip_dst = dst;
580 ip->ip_ttl = ttl;
581 ip->ip_len = htons (sendlen);
582
583 if (PIM_DEBUG_PIM_PACKETS) {
584 struct pim_msg_header *header = (struct pim_msg_header *)pim_msg;
585 char dst_str[INET_ADDRSTRLEN];
586 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
587 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
588 __PRETTY_FUNCTION__,
589 dst_str, ifname, pim_msg_size,
590 header->checksum);
591 }
592
593 memset(&to, 0, sizeof(to));
594 to.sin_family = AF_INET;
595 to.sin_addr = dst;
596 tolen = sizeof(to);
597
598 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
599 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
600 }
601
602 pim_msg_send_frame (fd, (char *)buffer, sendlen,
603 (struct sockaddr *)&to, tolen);
604 return 0;
605 }
606
607 static int hello_send(struct interface *ifp,
608 uint16_t holdtime)
609 {
610 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
611 struct pim_interface *pim_ifp;
612 int pim_tlv_size;
613 int pim_msg_size;
614
615 pim_ifp = ifp->info;
616
617 if (PIM_DEBUG_PIM_HELLO) {
618 char dst_str[INET_ADDRSTRLEN];
619 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str));
620 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",
621 __PRETTY_FUNCTION__,
622 dst_str, ifp->name,
623 holdtime,
624 pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec,
625 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
626 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
627 listcount(ifp->connected));
628 }
629
630 pim_tlv_size = pim_hello_build_tlv(ifp->name,
631 pim_msg + PIM_PIM_MIN_LEN,
632 sizeof(pim_msg) - PIM_PIM_MIN_LEN,
633 holdtime,
634 pim_ifp->pim_dr_priority,
635 pim_ifp->pim_generation_id,
636 pim_ifp->pim_propagation_delay_msec,
637 pim_ifp->pim_override_interval_msec,
638 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
639 ifp->connected);
640 if (pim_tlv_size < 0) {
641 return -1;
642 }
643
644 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
645
646 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
647 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
648
649 pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO);
650
651 if (pim_msg_send(pim_ifp->pim_sock_fd,
652 pim_ifp->primary_address,
653 qpim_all_pim_routers_addr,
654 pim_msg,
655 pim_msg_size,
656 ifp->name)) {
657 if (PIM_DEBUG_PIM_HELLO) {
658 zlog_debug("%s: could not send PIM message on interface %s",
659 __PRETTY_FUNCTION__, ifp->name);
660 }
661 return -2;
662 }
663
664 return 0;
665 }
666
667 static int pim_hello_send(struct interface *ifp,
668 uint16_t holdtime)
669 {
670 struct pim_interface *pim_ifp;
671
672 zassert(ifp);
673 pim_ifp = ifp->info;
674 zassert(pim_ifp);
675
676 if (if_is_loopback (ifp))
677 return 0;
678
679 if (hello_send(ifp, holdtime)) {
680 ++pim_ifp->pim_ifstat_hello_sendfail;
681
682 if (PIM_DEBUG_PIM_HELLO) {
683 zlog_warn("Could not send PIM hello on interface %s",
684 ifp->name);
685 }
686 return -1;
687 }
688
689 ++pim_ifp->pim_ifstat_hello_sent;
690
691 return 0;
692 }
693
694 static void hello_resched(struct interface *ifp)
695 {
696 struct pim_interface *pim_ifp;
697
698 zassert(ifp);
699 pim_ifp = ifp->info;
700 zassert(pim_ifp);
701
702 if (PIM_DEBUG_PIM_HELLO) {
703 zlog_debug("Rescheduling %d sec hello on interface %s",
704 pim_ifp->pim_hello_period, ifp->name);
705 }
706 THREAD_OFF(pim_ifp->t_pim_hello_timer);
707 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
708 on_pim_hello_send,
709 ifp, pim_ifp->pim_hello_period);
710 }
711
712 /*
713 Periodic hello timer
714 */
715 static int on_pim_hello_send(struct thread *t)
716 {
717 struct pim_interface *pim_ifp;
718 struct interface *ifp;
719
720 ifp = THREAD_ARG(t);
721
722 pim_ifp = ifp->info;
723
724 /*
725 * Schedule next hello
726 */
727 pim_ifp->t_pim_hello_timer = NULL;
728 hello_resched(ifp);
729
730 /*
731 * Send hello
732 */
733 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
734 }
735
736 /*
737 RFC 4601: 4.3.1. Sending Hello Messages
738
739 Thus, if a router needs to send a Join/Prune or Assert message on an
740 interface on which it has not yet sent a Hello message with the
741 currently configured IP address, then it MUST immediately send the
742 relevant Hello message without waiting for the Hello Timer to
743 expire, followed by the Join/Prune or Assert message.
744 */
745 void pim_hello_restart_now(struct interface *ifp)
746 {
747 struct pim_interface *pim_ifp;
748
749 zassert(ifp);
750 pim_ifp = ifp->info;
751 zassert(pim_ifp);
752
753 /*
754 * Reset next hello timer
755 */
756 hello_resched(ifp);
757
758 /*
759 * Immediately send hello
760 */
761 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
762 }
763
764 /*
765 RFC 4601: 4.3.1. Sending Hello Messages
766
767 To allow new or rebooting routers to learn of PIM neighbors quickly,
768 when a Hello message is received from a new neighbor, or a Hello
769 message with a new GenID is received from an existing neighbor, a
770 new Hello message should be sent on this interface after a
771 randomized delay between 0 and Triggered_Hello_Delay.
772 */
773 void pim_hello_restart_triggered(struct interface *ifp)
774 {
775 struct pim_interface *pim_ifp;
776 int triggered_hello_delay_msec;
777 int random_msec;
778
779 zassert(ifp);
780 pim_ifp = ifp->info;
781 zassert(pim_ifp);
782
783 /*
784 * There exists situations where we have the a RPF out this
785 * interface, but we haven't formed a neighbor yet. This
786 * happens especially during interface flaps. While
787 * we would like to handle this more gracefully in other
788 * parts of the code. In order to get us up and running
789 * let's just send the hello immediate'ish
790 * This should be revisited when we get nexthop tracking
791 * in and when we have a better handle on safely
792 * handling the rpf information for upstreams that
793 * we cannot legally reach yet.
794 */
795 triggered_hello_delay_msec = 1;
796 //triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
797
798 if (pim_ifp->t_pim_hello_timer) {
799 long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
800 if (remain_msec <= triggered_hello_delay_msec) {
801 /* Rescheduling hello would increase the delay, then it's faster
802 to just wait for the scheduled periodic hello. */
803 return;
804 }
805
806 THREAD_OFF(pim_ifp->t_pim_hello_timer);
807 pim_ifp->t_pim_hello_timer = NULL;
808 }
809
810 random_msec = triggered_hello_delay_msec;
811 //random_msec = random() % (triggered_hello_delay_msec + 1);
812
813 if (PIM_DEBUG_PIM_HELLO) {
814 zlog_debug("Scheduling %d msec triggered hello on interface %s",
815 random_msec, ifp->name);
816 }
817
818 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
819 on_pim_hello_send,
820 ifp, random_msec);
821 }
822
823 int pim_sock_add(struct interface *ifp)
824 {
825 struct pim_interface *pim_ifp;
826 uint32_t old_genid;
827
828 pim_ifp = ifp->info;
829 zassert(pim_ifp);
830
831 if (pim_ifp->pim_sock_fd >= 0) {
832 if (PIM_DEBUG_PIM_PACKETS)
833 zlog_debug("Can't recreate existing PIM socket fd=%d for interface %s",
834 pim_ifp->pim_sock_fd, ifp->name);
835 return -1;
836 }
837
838 pim_ifp->pim_sock_fd = pim_sock_open(ifp);
839 if (pim_ifp->pim_sock_fd < 0) {
840 if (PIM_DEBUG_PIM_PACKETS)
841 zlog_debug("Could not open PIM socket on interface %s",
842 ifp->name);
843 return -2;
844 }
845
846 pim_socket_ip_hdr (pim_ifp->pim_sock_fd);
847
848 pim_ifp->t_pim_sock_read = NULL;
849 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
850
851 /*
852 * Just ensure that the new generation id
853 * actually chooses something different.
854 * Actually ran across a case where this
855 * happened, pre-switch to random().
856 * While this is unlikely to happen now
857 * let's make sure it doesn't.
858 */
859 old_genid = pim_ifp->pim_generation_id;
860
861 while (old_genid == pim_ifp->pim_generation_id)
862 pim_ifp->pim_generation_id = random();
863
864 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
865 ifp->name, ifp->ifindex);
866
867 /*
868 * Start receiving PIM messages
869 */
870 pim_sock_read_on(ifp);
871
872 /*
873 * Start sending PIM hello's
874 */
875 pim_hello_restart_triggered(ifp);
876
877 return 0;
878 }