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