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