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