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