]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_pim.c
pimd: Trust the recvfromto ifindex information
[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(ifp, 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 /*
324 * What? So with vrf's the incoming packet is received
325 * on the vrf interface but recvfromto above returns
326 * the right ifindex, so just use it. We know
327 * it's the right interface because we bind to it
328 */
329 ifp = if_lookup_by_index(ifindex, pim_ifp->pim->vrf_id);
330
331 int fail = pim_pim_packet(ifp, buf, len);
332 if (fail) {
333 if (PIM_DEBUG_PIM_PACKETS)
334 zlog_debug("%s: pim_pim_packet() return=%d",
335 __PRETTY_FUNCTION__, fail);
336 goto done;
337 }
338
339 count++;
340 if (count % qpim_packet_process == 0)
341 cont = 0;
342 }
343
344 result = 0; /* good */
345
346 done:
347 pim_sock_read_on(ifp);
348
349 if (result) {
350 ++pim_ifp->pim_ifstat_hello_recvfail;
351 }
352
353 return result;
354 }
355
356 static void pim_sock_read_on(struct interface *ifp)
357 {
358 struct pim_interface *pim_ifp;
359
360 zassert(ifp);
361 zassert(ifp->info);
362
363 pim_ifp = ifp->info;
364
365 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
366 zlog_debug("Scheduling READ event on PIM socket fd=%d",
367 pim_ifp->pim_sock_fd);
368 }
369 pim_ifp->t_pim_sock_read = NULL;
370 thread_add_read(master, pim_sock_read, ifp, pim_ifp->pim_sock_fd,
371 &pim_ifp->t_pim_sock_read);
372 }
373
374 static int pim_sock_open(struct interface *ifp)
375 {
376 int fd;
377 struct pim_interface *pim_ifp = ifp->info;
378
379 fd = pim_socket_mcast(IPPROTO_PIM, pim_ifp->primary_address, ifp,
380 0 /* loop=false */);
381 if (fd < 0)
382 return -1;
383
384 if (pim_socket_join(fd, qpim_all_pim_routers_addr,
385 pim_ifp->primary_address, ifp->ifindex)) {
386 close(fd);
387 return -2;
388 }
389
390 return fd;
391 }
392
393 void pim_ifstat_reset(struct interface *ifp)
394 {
395 struct pim_interface *pim_ifp;
396
397 zassert(ifp);
398
399 pim_ifp = ifp->info;
400 if (!pim_ifp) {
401 return;
402 }
403
404 pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
405 pim_ifp->pim_ifstat_hello_sent = 0;
406 pim_ifp->pim_ifstat_hello_sendfail = 0;
407 pim_ifp->pim_ifstat_hello_recv = 0;
408 pim_ifp->pim_ifstat_hello_recvfail = 0;
409 }
410
411 void pim_sock_reset(struct interface *ifp)
412 {
413 struct pim_interface *pim_ifp;
414
415 zassert(ifp);
416 zassert(ifp->info);
417
418 pim_ifp = ifp->info;
419
420 pim_ifp->primary_address = pim_find_primary_addr(ifp);
421
422 pim_ifp->pim_sock_fd = -1;
423 pim_ifp->pim_sock_creation = 0;
424 pim_ifp->t_pim_sock_read = NULL;
425
426 pim_ifp->t_pim_hello_timer = NULL;
427 pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
428 pim_ifp->pim_default_holdtime =
429 -1; /* unset: means 3.5 * pim_hello_period */
430 pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
431 pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
432 pim_ifp->pim_propagation_delay_msec =
433 PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
434 pim_ifp->pim_override_interval_msec =
435 PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
436 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
437 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
438 } else {
439 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
440 }
441
442 /* neighbors without lan_delay */
443 pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
444 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
445 pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
446
447 /* DR Election */
448 pim_ifp->pim_dr_election_last = 0; /* timestamp */
449 pim_ifp->pim_dr_election_count = 0;
450 pim_ifp->pim_dr_election_changes = 0;
451 pim_ifp->pim_dr_num_nondrpri_neighbors =
452 0; /* neighbors without dr_pri */
453 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
454
455 pim_ifstat_reset(ifp);
456 }
457
458 static uint16_t ip_id = 0;
459
460
461 static int pim_msg_send_frame(int fd, char *buf, size_t len,
462 struct sockaddr *dst, size_t salen)
463 {
464 struct ip *ip = (struct ip *)buf;
465
466 while (sendto(fd, buf, len, MSG_DONTWAIT, dst, salen) < 0) {
467 char dst_str[INET_ADDRSTRLEN];
468
469 switch (errno) {
470 case EMSGSIZE: {
471 size_t hdrsize = sizeof(struct ip);
472 size_t newlen1 = ((len - hdrsize) / 2) & 0xFFF8;
473 size_t sendlen = newlen1 + hdrsize;
474 size_t offset = ntohs(ip->ip_off);
475
476 ip->ip_len = htons(sendlen);
477 ip->ip_off = htons(offset | IP_MF);
478 if (pim_msg_send_frame(fd, buf, sendlen, dst, salen)
479 == 0) {
480 struct ip *ip2 = (struct ip *)(buf + newlen1);
481 size_t newlen2 = len - sendlen;
482 sendlen = newlen2 + hdrsize;
483
484 memcpy(ip2, ip, hdrsize);
485 ip2->ip_len = htons(sendlen);
486 ip2->ip_off = htons(offset + (newlen1 >> 3));
487 return pim_msg_send_frame(fd, (char *)ip2,
488 sendlen, dst, salen);
489 }
490 }
491
492 return -1;
493 break;
494 default:
495 if (PIM_DEBUG_PIM_PACKETS) {
496 pim_inet4_dump("<dst?>", ip->ip_dst, dst_str,
497 sizeof(dst_str));
498 zlog_warn(
499 "%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
500 __PRETTY_FUNCTION__, dst_str, fd, len,
501 errno, safe_strerror(errno));
502 }
503 return -1;
504 break;
505 }
506 }
507
508 return 0;
509 }
510
511 int pim_msg_send(int fd, struct in_addr src, struct in_addr dst,
512 uint8_t *pim_msg, int pim_msg_size, const char *ifname)
513 {
514 struct sockaddr_in to;
515 socklen_t tolen;
516 unsigned char buffer[10000];
517 unsigned char *msg_start;
518 uint8_t ttl = MAXTTL;
519 struct pim_msg_header *header;
520 struct ip *ip;
521
522 memset(buffer, 0, 10000);
523 int sendlen = sizeof(struct ip) + pim_msg_size;
524
525 msg_start = buffer + sizeof(struct ip);
526 memcpy(msg_start, pim_msg, pim_msg_size);
527
528 header = (struct pim_msg_header *)pim_msg;
529 /*
530 * Omnios apparently doesn't have a #define for IP default
531 * ttl that is the same as all other platforms.
532 */
533 #ifndef IPDEFTTL
534 #define IPDEFTTL 64
535 #endif
536 /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
537 switch (header->type) {
538 case PIM_MSG_TYPE_HELLO:
539 case PIM_MSG_TYPE_JOIN_PRUNE:
540 case PIM_MSG_TYPE_BOOTSTRAP:
541 case PIM_MSG_TYPE_ASSERT:
542 ttl = 1;
543 break;
544 case PIM_MSG_TYPE_REGISTER:
545 case PIM_MSG_TYPE_REG_STOP:
546 case PIM_MSG_TYPE_GRAFT:
547 case PIM_MSG_TYPE_GRAFT_ACK:
548 case PIM_MSG_TYPE_CANDIDATE:
549 ttl = IPDEFTTL;
550 break;
551 default:
552 ttl = MAXTTL;
553 break;
554 }
555
556 ip = (struct ip *)buffer;
557 ip->ip_id = htons(++ip_id);
558 ip->ip_hl = 5;
559 ip->ip_v = 4;
560 ip->ip_p = PIM_IP_PROTO_PIM;
561 ip->ip_src = src;
562 ip->ip_dst = dst;
563 ip->ip_ttl = ttl;
564 ip->ip_len = htons(sendlen);
565
566 if (PIM_DEBUG_PIM_PACKETS) {
567 struct pim_msg_header *header =
568 (struct pim_msg_header *)pim_msg;
569 char dst_str[INET_ADDRSTRLEN];
570 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
571 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
572 __PRETTY_FUNCTION__, dst_str, ifname, pim_msg_size,
573 header->checksum);
574 }
575
576 memset(&to, 0, sizeof(to));
577 to.sin_family = AF_INET;
578 to.sin_addr = dst;
579 tolen = sizeof(to);
580
581 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
582 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
583 }
584
585 pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to,
586 tolen);
587 return 0;
588 }
589
590 static int hello_send(struct interface *ifp, uint16_t holdtime)
591 {
592 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
593 struct pim_interface *pim_ifp;
594 int pim_tlv_size;
595 int pim_msg_size;
596
597 pim_ifp = ifp->info;
598
599 if (PIM_DEBUG_PIM_HELLO) {
600 char dst_str[INET_ADDRSTRLEN];
601 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str,
602 sizeof(dst_str));
603 zlog_debug(
604 "%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",
605 __PRETTY_FUNCTION__, dst_str, ifp->name, holdtime,
606 pim_ifp->pim_propagation_delay_msec,
607 pim_ifp->pim_override_interval_msec,
608 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(
609 pim_ifp->options),
610 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
611 listcount(ifp->connected));
612 }
613
614 pim_tlv_size = pim_hello_build_tlv(
615 ifp, pim_msg + PIM_PIM_MIN_LEN,
616 sizeof(pim_msg) - PIM_PIM_MIN_LEN, holdtime,
617 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
618 pim_ifp->pim_propagation_delay_msec,
619 pim_ifp->pim_override_interval_msec,
620 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options));
621 if (pim_tlv_size < 0) {
622 return -1;
623 }
624
625 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
626
627 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
628 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
629
630 pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO);
631
632 if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
633 qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
634 ifp->name)) {
635 if (PIM_DEBUG_PIM_HELLO) {
636 zlog_debug(
637 "%s: could not send PIM message on interface %s",
638 __PRETTY_FUNCTION__, ifp->name);
639 }
640 return -2;
641 }
642
643 return 0;
644 }
645
646 static int pim_hello_send(struct interface *ifp, uint16_t holdtime)
647 {
648 struct pim_interface *pim_ifp = ifp->info;
649
650 if (pim_if_is_loopback(pim_ifp->pim, ifp))
651 return 0;
652
653 if (hello_send(ifp, holdtime)) {
654 ++pim_ifp->pim_ifstat_hello_sendfail;
655
656 if (PIM_DEBUG_PIM_HELLO) {
657 zlog_warn("Could not send PIM hello on interface %s",
658 ifp->name);
659 }
660 return -1;
661 }
662
663 ++pim_ifp->pim_ifstat_hello_sent;
664
665 return 0;
666 }
667
668 static void hello_resched(struct interface *ifp)
669 {
670 struct pim_interface *pim_ifp;
671
672 zassert(ifp);
673 pim_ifp = ifp->info;
674 zassert(pim_ifp);
675
676 if (PIM_DEBUG_PIM_HELLO) {
677 zlog_debug("Rescheduling %d sec hello on interface %s",
678 pim_ifp->pim_hello_period, ifp->name);
679 }
680 THREAD_OFF(pim_ifp->t_pim_hello_timer);
681 thread_add_timer(master, on_pim_hello_send, ifp,
682 pim_ifp->pim_hello_period,
683 &pim_ifp->t_pim_hello_timer);
684 }
685
686 /*
687 Periodic hello timer
688 */
689 static int on_pim_hello_send(struct thread *t)
690 {
691 struct pim_interface *pim_ifp;
692 struct interface *ifp;
693
694 ifp = THREAD_ARG(t);
695
696 pim_ifp = ifp->info;
697
698 /*
699 * Schedule next hello
700 */
701 hello_resched(ifp);
702
703 /*
704 * Send hello
705 */
706 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
707 }
708
709 /*
710 RFC 4601: 4.3.1. Sending Hello Messages
711
712 Thus, if a router needs to send a Join/Prune or Assert message on an
713 interface on which it has not yet sent a Hello message with the
714 currently configured IP address, then it MUST immediately send the
715 relevant Hello message without waiting for the Hello Timer to
716 expire, followed by the Join/Prune or Assert message.
717 */
718 void pim_hello_restart_now(struct interface *ifp)
719 {
720 struct pim_interface *pim_ifp;
721
722 zassert(ifp);
723 pim_ifp = ifp->info;
724 zassert(pim_ifp);
725
726 /*
727 * Reset next hello timer
728 */
729 hello_resched(ifp);
730
731 /*
732 * Immediately send hello
733 */
734 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
735 }
736
737 /*
738 RFC 4601: 4.3.1. Sending Hello Messages
739
740 To allow new or rebooting routers to learn of PIM neighbors quickly,
741 when a Hello message is received from a new neighbor, or a Hello
742 message with a new GenID is received from an existing neighbor, a
743 new Hello message should be sent on this interface after a
744 randomized delay between 0 and Triggered_Hello_Delay.
745 */
746 void pim_hello_restart_triggered(struct interface *ifp)
747 {
748 struct pim_interface *pim_ifp;
749 int triggered_hello_delay_msec;
750 int random_msec;
751
752 zassert(ifp);
753 pim_ifp = ifp->info;
754 zassert(pim_ifp);
755
756 /*
757 * There exists situations where we have the a RPF out this
758 * interface, but we haven't formed a neighbor yet. This
759 * happens especially during interface flaps. While
760 * we would like to handle this more gracefully in other
761 * parts of the code. In order to get us up and running
762 * let's just send the hello immediate'ish
763 * This should be revisited when we get nexthop tracking
764 * in and when we have a better handle on safely
765 * handling the rpf information for upstreams that
766 * we cannot legally reach yet.
767 */
768 triggered_hello_delay_msec = 1;
769 // triggered_hello_delay_msec = 1000 *
770 // pim_ifp->pim_triggered_hello_delay;
771
772 if (pim_ifp->t_pim_hello_timer) {
773 long remain_msec =
774 pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
775 if (remain_msec <= triggered_hello_delay_msec) {
776 /* Rescheduling hello would increase the delay, then
777 it's faster
778 to just wait for the scheduled periodic hello. */
779 return;
780 }
781
782 THREAD_OFF(pim_ifp->t_pim_hello_timer);
783 }
784
785 random_msec = triggered_hello_delay_msec;
786 // random_msec = random() % (triggered_hello_delay_msec + 1);
787
788 if (PIM_DEBUG_PIM_HELLO) {
789 zlog_debug("Scheduling %d msec triggered hello on interface %s",
790 random_msec, ifp->name);
791 }
792
793 thread_add_timer_msec(master, on_pim_hello_send, ifp, random_msec,
794 &pim_ifp->t_pim_hello_timer);
795 }
796
797 int pim_sock_add(struct interface *ifp)
798 {
799 struct pim_interface *pim_ifp;
800 uint32_t old_genid;
801
802 pim_ifp = ifp->info;
803 zassert(pim_ifp);
804
805 if (pim_ifp->pim_sock_fd >= 0) {
806 if (PIM_DEBUG_PIM_PACKETS)
807 zlog_debug(
808 "Can't recreate existing PIM socket fd=%d for interface %s",
809 pim_ifp->pim_sock_fd, ifp->name);
810 return -1;
811 }
812
813 pim_ifp->pim_sock_fd = pim_sock_open(ifp);
814 if (pim_ifp->pim_sock_fd < 0) {
815 if (PIM_DEBUG_PIM_PACKETS)
816 zlog_debug("Could not open PIM socket on interface %s",
817 ifp->name);
818 return -2;
819 }
820
821 pim_socket_ip_hdr(pim_ifp->pim_sock_fd);
822
823 pim_ifp->t_pim_sock_read = NULL;
824 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
825
826 /*
827 * Just ensure that the new generation id
828 * actually chooses something different.
829 * Actually ran across a case where this
830 * happened, pre-switch to random().
831 * While this is unlikely to happen now
832 * let's make sure it doesn't.
833 */
834 old_genid = pim_ifp->pim_generation_id;
835
836 while (old_genid == pim_ifp->pim_generation_id)
837 pim_ifp->pim_generation_id = random();
838
839 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp->name,
840 ifp->ifindex);
841
842 /*
843 * Start receiving PIM messages
844 */
845 pim_sock_read_on(ifp);
846
847 /*
848 * Start sending PIM hello's
849 */
850 pim_hello_restart_triggered(ifp);
851
852 return 0;
853 }