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