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