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