]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_pim.c
Merge pull request #5881 from patrasar/2386420
[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
505 pim_ifstat_reset(ifp);
506 }
507
508 static uint16_t ip_id = 0;
509
510
511 static int pim_msg_send_frame(int fd, char *buf, size_t len,
512 struct sockaddr *dst, size_t salen)
513 {
514 struct ip *ip = (struct ip *)buf;
515
516 while (sendto(fd, buf, len, MSG_DONTWAIT, dst, salen) < 0) {
517 char dst_str[INET_ADDRSTRLEN];
518
519 switch (errno) {
520 case EMSGSIZE: {
521 size_t hdrsize = sizeof(struct ip);
522 size_t newlen1 = ((len - hdrsize) / 2) & 0xFFF8;
523 size_t sendlen = newlen1 + hdrsize;
524 size_t offset = ntohs(ip->ip_off);
525
526 ip->ip_len = htons(sendlen);
527 ip->ip_off = htons(offset | IP_MF);
528 if (pim_msg_send_frame(fd, buf, sendlen, dst, salen)
529 == 0) {
530 struct ip *ip2 = (struct ip *)(buf + newlen1);
531 size_t newlen2 = len - sendlen;
532 sendlen = newlen2 + hdrsize;
533
534 memcpy(ip2, ip, hdrsize);
535 ip2->ip_len = htons(sendlen);
536 ip2->ip_off = htons(offset + (newlen1 >> 3));
537 return pim_msg_send_frame(fd, (char *)ip2,
538 sendlen, dst, salen);
539 }
540 }
541
542 return -1;
543 default:
544 if (PIM_DEBUG_PIM_PACKETS) {
545 pim_inet4_dump("<dst?>", ip->ip_dst, dst_str,
546 sizeof(dst_str));
547 zlog_warn(
548 "%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
549 __func__, dst_str, fd, len, errno,
550 safe_strerror(errno));
551 }
552 return -1;
553 }
554 }
555
556 return 0;
557 }
558
559 int pim_msg_send(int fd, struct in_addr src, struct in_addr dst,
560 uint8_t *pim_msg, int pim_msg_size, const char *ifname)
561 {
562 struct sockaddr_in to;
563 socklen_t tolen;
564 unsigned char buffer[10000];
565 unsigned char *msg_start;
566 uint8_t ttl;
567 struct pim_msg_header *header;
568 struct ip *ip;
569
570 memset(buffer, 0, 10000);
571 int sendlen = sizeof(struct ip) + pim_msg_size;
572
573 msg_start = buffer + sizeof(struct ip);
574 memcpy(msg_start, pim_msg, pim_msg_size);
575
576 header = (struct pim_msg_header *)pim_msg;
577 /*
578 * Omnios apparently doesn't have a #define for IP default
579 * ttl that is the same as all other platforms.
580 */
581 #ifndef IPDEFTTL
582 #define IPDEFTTL 64
583 #endif
584 /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
585 switch (header->type) {
586 case PIM_MSG_TYPE_HELLO:
587 case PIM_MSG_TYPE_JOIN_PRUNE:
588 case PIM_MSG_TYPE_BOOTSTRAP:
589 case PIM_MSG_TYPE_ASSERT:
590 ttl = 1;
591 break;
592 case PIM_MSG_TYPE_REGISTER:
593 case PIM_MSG_TYPE_REG_STOP:
594 case PIM_MSG_TYPE_GRAFT:
595 case PIM_MSG_TYPE_GRAFT_ACK:
596 case PIM_MSG_TYPE_CANDIDATE:
597 ttl = IPDEFTTL;
598 break;
599 default:
600 ttl = MAXTTL;
601 break;
602 }
603
604 ip = (struct ip *)buffer;
605 ip->ip_id = htons(++ip_id);
606 ip->ip_hl = 5;
607 ip->ip_v = 4;
608 ip->ip_tos = IPTOS_PREC_INTERNETCONTROL;
609 ip->ip_p = PIM_IP_PROTO_PIM;
610 ip->ip_src = src;
611 ip->ip_dst = dst;
612 ip->ip_ttl = ttl;
613 ip->ip_len = htons(sendlen);
614
615 if (PIM_DEBUG_PIM_PACKETS) {
616 char dst_str[INET_ADDRSTRLEN];
617 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
618 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x", __func__,
619 dst_str, ifname, pim_msg_size, header->checksum);
620 }
621
622 memset(&to, 0, sizeof(to));
623 to.sin_family = AF_INET;
624 to.sin_addr = dst;
625 tolen = sizeof(to);
626
627 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
628 pim_pkt_dump(__func__, pim_msg, pim_msg_size);
629 }
630
631 pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to,
632 tolen);
633 return 0;
634 }
635
636 static int hello_send(struct interface *ifp, uint16_t holdtime)
637 {
638 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
639 struct pim_interface *pim_ifp;
640 int pim_tlv_size;
641 int pim_msg_size;
642
643 pim_ifp = ifp->info;
644
645 if (PIM_DEBUG_PIM_HELLO) {
646 char dst_str[INET_ADDRSTRLEN];
647 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str,
648 sizeof(dst_str));
649 zlog_debug(
650 "%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",
651 __func__, dst_str, ifp->name, holdtime,
652 pim_ifp->pim_propagation_delay_msec,
653 pim_ifp->pim_override_interval_msec,
654 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(
655 pim_ifp->options),
656 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
657 listcount(ifp->connected));
658 }
659
660 pim_tlv_size = pim_hello_build_tlv(
661 ifp, pim_msg + PIM_PIM_MIN_LEN,
662 sizeof(pim_msg) - PIM_PIM_MIN_LEN, holdtime,
663 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
664 pim_ifp->pim_propagation_delay_msec,
665 pim_ifp->pim_override_interval_msec,
666 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options));
667 if (pim_tlv_size < 0) {
668 return -1;
669 }
670
671 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
672
673 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
674 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
675
676 pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO, false);
677
678 if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
679 qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
680 ifp->name)) {
681 if (PIM_DEBUG_PIM_HELLO) {
682 zlog_debug(
683 "%s: could not send PIM message on interface %s",
684 __func__, ifp->name);
685 }
686 return -2;
687 }
688
689 return 0;
690 }
691
692 int pim_hello_send(struct interface *ifp, uint16_t holdtime)
693 {
694 struct pim_interface *pim_ifp = ifp->info;
695
696 if (if_is_loopback_or_vrf(ifp))
697 return 0;
698
699 if (hello_send(ifp, holdtime)) {
700 ++pim_ifp->pim_ifstat_hello_sendfail;
701
702 if (PIM_DEBUG_PIM_HELLO) {
703 zlog_warn("Could not send PIM hello on interface %s",
704 ifp->name);
705 }
706 return -1;
707 }
708
709 ++pim_ifp->pim_ifstat_hello_sent;
710
711 return 0;
712 }
713
714 static void hello_resched(struct interface *ifp)
715 {
716 struct pim_interface *pim_ifp;
717
718 pim_ifp = ifp->info;
719
720 if (PIM_DEBUG_PIM_HELLO) {
721 zlog_debug("Rescheduling %d sec hello on interface %s",
722 pim_ifp->pim_hello_period, ifp->name);
723 }
724 THREAD_OFF(pim_ifp->t_pim_hello_timer);
725 thread_add_timer(router->master, on_pim_hello_send, ifp,
726 pim_ifp->pim_hello_period,
727 &pim_ifp->t_pim_hello_timer);
728 }
729
730 /*
731 Periodic hello timer
732 */
733 static int on_pim_hello_send(struct thread *t)
734 {
735 struct pim_interface *pim_ifp;
736 struct interface *ifp;
737
738 ifp = THREAD_ARG(t);
739 pim_ifp = ifp->info;
740
741 /*
742 * Schedule next hello
743 */
744 hello_resched(ifp);
745
746 /*
747 * Send hello
748 */
749 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
750 }
751
752 /*
753 RFC 4601: 4.3.1. Sending Hello Messages
754
755 Thus, if a router needs to send a Join/Prune or Assert message on an
756 interface on which it has not yet sent a Hello message with the
757 currently configured IP address, then it MUST immediately send the
758 relevant Hello message without waiting for the Hello Timer to
759 expire, followed by the Join/Prune or Assert message.
760 */
761 void pim_hello_restart_now(struct interface *ifp)
762 {
763 struct pim_interface *pim_ifp;
764
765 pim_ifp = ifp->info;
766
767 /*
768 * Reset next hello timer
769 */
770 hello_resched(ifp);
771
772 /*
773 * Immediately send hello
774 */
775 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
776 }
777
778 /*
779 RFC 4601: 4.3.1. Sending Hello Messages
780
781 To allow new or rebooting routers to learn of PIM neighbors quickly,
782 when a Hello message is received from a new neighbor, or a Hello
783 message with a new GenID is received from an existing neighbor, a
784 new Hello message should be sent on this interface after a
785 randomized delay between 0 and Triggered_Hello_Delay.
786 */
787 void pim_hello_restart_triggered(struct interface *ifp)
788 {
789 struct pim_interface *pim_ifp;
790 int triggered_hello_delay_msec;
791 int random_msec;
792
793 pim_ifp = ifp->info;
794
795 /*
796 * No need to ever start loopback or vrf device hello's
797 */
798 if (if_is_loopback_or_vrf(ifp))
799 return;
800
801 /*
802 * There exists situations where we have the a RPF out this
803 * interface, but we haven't formed a neighbor yet. This
804 * happens especially during interface flaps. While
805 * we would like to handle this more gracefully in other
806 * parts of the code. In order to get us up and running
807 * let's just send the hello immediate'ish
808 * This should be revisited when we get nexthop tracking
809 * in and when we have a better handle on safely
810 * handling the rpf information for upstreams that
811 * we cannot legally reach yet.
812 */
813 triggered_hello_delay_msec = 1;
814 // triggered_hello_delay_msec = 1000 *
815 // pim_ifp->pim_triggered_hello_delay;
816
817 if (pim_ifp->t_pim_hello_timer) {
818 long remain_msec =
819 pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
820 if (remain_msec <= triggered_hello_delay_msec) {
821 /* Rescheduling hello would increase the delay, then
822 it's faster
823 to just wait for the scheduled periodic hello. */
824 return;
825 }
826
827 THREAD_OFF(pim_ifp->t_pim_hello_timer);
828 }
829
830 random_msec = triggered_hello_delay_msec;
831 // random_msec = random() % (triggered_hello_delay_msec + 1);
832
833 if (PIM_DEBUG_PIM_HELLO) {
834 zlog_debug("Scheduling %d msec triggered hello on interface %s",
835 random_msec, ifp->name);
836 }
837
838 thread_add_timer_msec(router->master, on_pim_hello_send, ifp,
839 random_msec, &pim_ifp->t_pim_hello_timer);
840 }
841
842 int pim_sock_add(struct interface *ifp)
843 {
844 struct pim_interface *pim_ifp;
845 uint32_t old_genid;
846
847 pim_ifp = ifp->info;
848 zassert(pim_ifp);
849
850 if (pim_ifp->pim_sock_fd >= 0) {
851 if (PIM_DEBUG_PIM_PACKETS)
852 zlog_debug(
853 "Can't recreate existing PIM socket fd=%d for interface %s",
854 pim_ifp->pim_sock_fd, ifp->name);
855 return -1;
856 }
857
858 pim_ifp->pim_sock_fd = pim_sock_open(ifp);
859 if (pim_ifp->pim_sock_fd < 0) {
860 if (PIM_DEBUG_PIM_PACKETS)
861 zlog_debug("Could not open PIM socket on interface %s",
862 ifp->name);
863 return -2;
864 }
865
866 pim_socket_ip_hdr(pim_ifp->pim_sock_fd);
867
868 pim_ifp->t_pim_sock_read = NULL;
869 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
870
871 /*
872 * Just ensure that the new generation id
873 * actually chooses something different.
874 * Actually ran across a case where this
875 * happened, pre-switch to random().
876 * While this is unlikely to happen now
877 * let's make sure it doesn't.
878 */
879 old_genid = pim_ifp->pim_generation_id;
880
881 while (old_genid == pim_ifp->pim_generation_id)
882 pim_ifp->pim_generation_id = frr_weak_random();
883
884 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp->name,
885 ifp->ifindex);
886
887 /*
888 * Start receiving PIM messages
889 */
890 pim_sock_read_on(ifp);
891
892 /*
893 * Start sending PIM hello's
894 */
895 pim_hello_restart_triggered(ifp);
896
897 return 0;
898 }