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