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