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