blob: cd8a29031f719b630112b7889a190b7a207595cf [file] [log] [blame]
Everton Marques871dbcf2009-08-11 15:43:05 -03001/*
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 $QuaggaId: $Format:%an, %ai, %h$ $
21*/
22
23#include <zebra.h>
24
25#include "log.h"
26#include "thread.h"
27#include "memory.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"
Everton Marques871dbcf2009-08-11 15:43:05 -030042
43static int on_pim_hello_send(struct thread *t);
44static int pim_hello_send(struct interface *ifp,
45 uint16_t holdtime);
46
47static void sock_close(struct interface *ifp)
48{
49 struct pim_interface *pim_ifp = ifp->info;
50
51 if (PIM_DEBUG_PIM_TRACE) {
52 if (pim_ifp->t_pim_sock_read) {
53 zlog_debug("Cancelling READ event for PIM socket fd=%d on interface %s",
54 pim_ifp->pim_sock_fd,
55 ifp->name);
56 }
57 }
58 THREAD_OFF(pim_ifp->t_pim_sock_read);
59
60 if (PIM_DEBUG_PIM_TRACE) {
61 if (pim_ifp->t_pim_hello_timer) {
62 zlog_debug("Cancelling PIM hello timer for interface %s",
63 ifp->name);
64 }
65 }
66 THREAD_OFF(pim_ifp->t_pim_hello_timer);
67
68 if (PIM_DEBUG_PIM_TRACE) {
69 zlog_debug("Deleting PIM socket fd=%d on interface %s",
70 pim_ifp->pim_sock_fd, ifp->name);
71 }
72
73 if (close(pim_ifp->pim_sock_fd)) {
74 zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
75 pim_ifp->pim_sock_fd, ifp->name,
Everton Marquese96f0af2009-08-11 15:48:02 -030076 errno, safe_strerror(errno));
Everton Marques871dbcf2009-08-11 15:43:05 -030077 }
78
79 pim_ifp->pim_sock_fd = -1;
80 pim_ifp->pim_sock_creation = 0;
81
82 zassert(pim_ifp->pim_sock_fd < 0);
83 zassert(!pim_ifp->t_pim_sock_read);
84 zassert(!pim_ifp->t_pim_hello_timer);
85 zassert(!pim_ifp->pim_sock_creation);
86}
87
88void pim_sock_delete(struct interface *ifp, const char *delete_message)
89{
90 zlog_info("PIM INTERFACE DOWN: on interface %s: %s",
91 ifp->name, delete_message);
92
Everton Marquese96f0af2009-08-11 15:48:02 -030093 if (!ifp->info) {
94 zlog_err("%s: %s: but PIM not enabled on interface %s (!)",
95 __PRETTY_FUNCTION__, delete_message, ifp->name);
96 return;
97 }
98
Everton Marques871dbcf2009-08-11 15:43:05 -030099 /*
100 RFC 4601: 4.3.1. Sending Hello Messages
101
102 Before an interface goes down or changes primary IP address, a Hello
103 message with a zero HoldTime should be sent immediately (with the
104 old IP address if the IP address changed).
105 */
106 pim_hello_send(ifp, 0 /* zero-sec holdtime */);
107
108 pim_neighbor_delete_all(ifp, delete_message);
109
110 sock_close(ifp);
111}
112
David Lamparterf8cfeb22012-02-16 04:31:08 +0000113int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
Everton Marques871dbcf2009-08-11 15:43:05 -0300114{
115 struct ip *ip_hdr;
116 size_t ip_hlen; /* ip header length in bytes */
117 char src_str[100];
118 char dst_str[100];
David Lamparterf8cfeb22012-02-16 04:31:08 +0000119 uint8_t *pim_msg;
Everton Marques871dbcf2009-08-11 15:43:05 -0300120 int pim_msg_len;
121 uint8_t pim_version;
122 uint8_t pim_type;
123 uint16_t pim_checksum; /* received checksum */
124 uint16_t checksum; /* computed checksum */
125 struct pim_neighbor *neigh;
126
127 if (!ifp->info) {
128 zlog_warn("%s: PIM not enabled on interface %s",
129 __PRETTY_FUNCTION__, ifp->name);
130 return -1;
131 }
132
133 if (len < sizeof(*ip_hdr)) {
David Lamparter5c697982012-02-16 04:47:56 +0100134 zlog_warn("PIM packet size=%zu shorter than minimum=%zu",
Everton Marques871dbcf2009-08-11 15:43:05 -0300135 len, sizeof(*ip_hdr));
136 return -1;
137 }
138
139 ip_hdr = (struct ip *) buf;
140
141 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
142 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str, sizeof(dst_str));
143
144 ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
145
146 if (PIM_DEBUG_PIM_PACKETS) {
David Lamparter5c697982012-02-16 04:47:56 +0100147 zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d",
Everton Marques871dbcf2009-08-11 15:43:05 -0300148 src_str, dst_str, ifp->name, len, ip_hlen, ip_hdr->ip_p);
149 }
150
151 if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) {
152 zlog_warn("IP packet protocol=%d is not PIM=%d",
153 ip_hdr->ip_p, PIM_IP_PROTO_PIM);
154 return -1;
155 }
156
157 if (ip_hlen < PIM_IP_HEADER_MIN_LEN) {
David Lamparter5c697982012-02-16 04:47:56 +0100158 zlog_warn("IP packet header size=%zu shorter than minimum=%d",
Everton Marques871dbcf2009-08-11 15:43:05 -0300159 ip_hlen, PIM_IP_HEADER_MIN_LEN);
160 return -1;
161 }
162 if (ip_hlen > PIM_IP_HEADER_MAX_LEN) {
David Lamparter5c697982012-02-16 04:47:56 +0100163 zlog_warn("IP packet header size=%zu greater than maximum=%d",
Everton Marques871dbcf2009-08-11 15:43:05 -0300164 ip_hlen, PIM_IP_HEADER_MAX_LEN);
165 return -1;
166 }
167
168 pim_msg = buf + ip_hlen;
169 pim_msg_len = len - ip_hlen;
170
Everton Marques62738042009-11-18 10:44:13 -0200171 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
172 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
173 }
174
Everton Marques871dbcf2009-08-11 15:43:05 -0300175 if (pim_msg_len < PIM_PIM_MIN_LEN) {
176 zlog_warn("PIM message size=%d shorter than minimum=%d",
177 pim_msg_len, PIM_PIM_MIN_LEN);
178 return -1;
179 }
180
181 pim_version = PIM_MSG_HDR_GET_VERSION(pim_msg);
182 pim_type = PIM_MSG_HDR_GET_TYPE(pim_msg);
183
184 if (pim_version != PIM_PROTO_VERSION) {
185 zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d",
186 ifp->name, pim_version);
187 return -1;
188 }
189
190 /* save received checksum */
191 pim_checksum = PIM_MSG_HDR_GET_CHECKSUM(pim_msg);
192
193 /* for computing checksum */
194 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0;
195
Everton Marques93911262014-09-18 11:10:58 -0300196 checksum = in_cksum(pim_msg, pim_msg_len);
Everton Marques871dbcf2009-08-11 15:43:05 -0300197 if (checksum != pim_checksum) {
198 zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
199 ifp->name, pim_checksum, checksum);
200 return -1;
201 }
202
203 if (PIM_DEBUG_PIM_PACKETS) {
204 zlog_debug("Recv PIM packet from %s to %s on %s: ttl=%d pim_version=%d pim_type=%d pim_msg_size=%d checksum=%x",
205 src_str, dst_str, ifp->name, ip_hdr->ip_ttl,
206 pim_version, pim_type, pim_msg_len, checksum);
207 }
208
209 if (pim_type == PIM_MSG_TYPE_HELLO) {
Everton Marques777fe1f2014-02-14 14:16:07 -0200210 int result = pim_hello_recv(ifp,
211 ip_hdr->ip_src,
212 pim_msg + PIM_MSG_HEADER_LEN,
213 pim_msg_len - PIM_MSG_HEADER_LEN);
Everton Marques777fe1f2014-02-14 14:16:07 -0200214 return result;
Everton Marques871dbcf2009-08-11 15:43:05 -0300215 }
216
217 neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
218 if (!neigh) {
219 zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
220 __FILE__, __PRETTY_FUNCTION__,
221 pim_type, src_str, ifp->name);
222 return -1;
223 }
224
225 switch (pim_type) {
226 case PIM_MSG_TYPE_JOIN_PRUNE:
227 return pim_joinprune_recv(ifp, neigh,
228 ip_hdr->ip_src,
229 pim_msg + PIM_MSG_HEADER_LEN,
230 pim_msg_len - PIM_MSG_HEADER_LEN);
231 case PIM_MSG_TYPE_ASSERT:
232 return pim_assert_recv(ifp, neigh,
233 ip_hdr->ip_src,
234 pim_msg + PIM_MSG_HEADER_LEN,
235 pim_msg_len - PIM_MSG_HEADER_LEN);
236 default:
237 zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s",
238 __FILE__, __PRETTY_FUNCTION__,
239 pim_type, src_str, ifp->name);
240 }
241
242 return -1;
243}
244
245static void pim_sock_read_on(struct interface *ifp);
246
247static int pim_sock_read(struct thread *t)
248{
249 struct interface *ifp;
250 struct pim_interface *pim_ifp;
251 int fd;
252 struct sockaddr_in from;
253 struct sockaddr_in to;
254 socklen_t fromlen = sizeof(from);
255 socklen_t tolen = sizeof(to);
David Lamparterf8cfeb22012-02-16 04:31:08 +0000256 uint8_t buf[PIM_PIM_BUFSIZE_READ];
Everton Marques871dbcf2009-08-11 15:43:05 -0300257 int len;
258 int ifindex = -1;
259 int result = -1; /* defaults to bad */
260
261 zassert(t);
262
263 ifp = THREAD_ARG(t);
264 zassert(ifp);
265
266 fd = THREAD_FD(t);
267
268 pim_ifp = ifp->info;
269 zassert(pim_ifp);
270
271 zassert(fd == pim_ifp->pim_sock_fd);
272
273 len = pim_socket_recvfromto(fd, buf, sizeof(buf),
274 &from, &fromlen,
275 &to, &tolen,
276 &ifindex);
277 if (len < 0) {
278 zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s",
Everton Marquese96f0af2009-08-11 15:48:02 -0300279 fd, errno, safe_strerror(errno));
Everton Marques871dbcf2009-08-11 15:43:05 -0300280 goto done;
281 }
282
283 if (PIM_DEBUG_PIM_PACKETS) {
284 char from_str[100];
285 char to_str[100];
286
287 if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str)))
288 sprintf(from_str, "<from?>");
289 if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str)))
290 sprintf(to_str, "<to?>");
291
292 zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)",
293 len, from_str, to_str, fd, ifindex, ifp->ifindex);
294 }
295
Everton Marques62738042009-11-18 10:44:13 -0200296 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
297 pim_pkt_dump(__PRETTY_FUNCTION__, buf, len);
298 }
299
Everton Marques871dbcf2009-08-11 15:43:05 -0300300#ifdef PIM_CHECK_RECV_IFINDEX_SANITY
301 /* ifindex sanity check */
302 if (ifindex != (int) ifp->ifindex) {
303 char from_str[100];
304 char to_str[100];
305 struct interface *recv_ifp;
306
307 if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
308 sprintf(from_str, "<from?>");
309 if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
310 sprintf(to_str, "<to?>");
311
312 recv_ifp = if_lookup_by_index(ifindex);
313 if (recv_ifp) {
314 zassert(ifindex == (int) recv_ifp->ifindex);
315 }
316
317#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
318 zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
319 from_str, to_str, fd,
320 ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
321 ifp->ifindex, ifp->name);
322#endif
323 goto done;
324 }
325#endif
326
Everton Marques777fe1f2014-02-14 14:16:07 -0200327 int fail = pim_pim_packet(ifp, buf, len);
328 if (fail) {
329 zlog_warn("%s: pim_pim_packet() return=%d",
330 __PRETTY_FUNCTION__, fail);
Everton Marques871dbcf2009-08-11 15:43:05 -0300331 goto done;
332 }
333
334 result = 0; /* good */
335
336 done:
337 pim_sock_read_on(ifp);
338
339 if (result) {
340 ++pim_ifp->pim_ifstat_hello_recvfail;
341 }
342
343 return result;
344}
345
346static void pim_sock_read_on(struct interface *ifp)
347{
348 struct pim_interface *pim_ifp;
349
350 zassert(ifp);
351 zassert(ifp->info);
352
353 pim_ifp = ifp->info;
354
355 if (PIM_DEBUG_PIM_TRACE) {
356 zlog_debug("Scheduling READ event on PIM socket fd=%d",
357 pim_ifp->pim_sock_fd);
358 }
359 pim_ifp->t_pim_sock_read = 0;
360 zassert(!pim_ifp->t_pim_sock_read);
361 THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
362 pim_ifp->pim_sock_fd);
363}
364
365static int pim_sock_open(struct in_addr ifaddr, int ifindex)
366{
367 int fd;
368
369 fd = pim_socket_mcast(IPPROTO_PIM, ifaddr, 0 /* loop=false */);
370 if (fd < 0)
371 return -1;
372
373 if (pim_socket_join(fd, qpim_all_pim_routers_addr, ifaddr, ifindex)) {
Donald Sharp44d03fd2015-09-08 15:02:07 -0400374 close(fd);
Everton Marques871dbcf2009-08-11 15:43:05 -0300375 return -2;
376 }
377
378 return fd;
379}
380
381void pim_ifstat_reset(struct interface *ifp)
382{
383 struct pim_interface *pim_ifp;
384
385 zassert(ifp);
386
387 pim_ifp = ifp->info;
388 if (!pim_ifp) {
389 return;
390 }
391
392 pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
393 pim_ifp->pim_ifstat_hello_sent = 0;
394 pim_ifp->pim_ifstat_hello_sendfail = 0;
395 pim_ifp->pim_ifstat_hello_recv = 0;
396 pim_ifp->pim_ifstat_hello_recvfail = 0;
397}
398
399void pim_sock_reset(struct interface *ifp)
400{
401 struct pim_interface *pim_ifp;
402
403 zassert(ifp);
404 zassert(ifp->info);
405
406 pim_ifp = ifp->info;
407
408 pim_ifp->primary_address = pim_find_primary_addr(ifp);
409
410 pim_ifp->pim_sock_fd = -1;
411 pim_ifp->pim_sock_creation = 0;
412 pim_ifp->t_pim_sock_read = 0;
413
414 pim_ifp->t_pim_hello_timer = 0;
415 pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
416 pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
417 pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
418 pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
419 pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
420 pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
421 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
422 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
423 }
424 else {
425 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
426 }
427
428 /* neighbors without lan_delay */
429 pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
430 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
431 pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
432
433 /* DR Election */
434 pim_ifp->pim_dr_election_last = 0; /* timestamp */
435 pim_ifp->pim_dr_election_count = 0;
Everton Marques777fe1f2014-02-14 14:16:07 -0200436 pim_ifp->pim_dr_election_changes = 0;
Everton Marques871dbcf2009-08-11 15:43:05 -0300437 pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */
438 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
439
440 pim_ifstat_reset(ifp);
441}
442
443int pim_msg_send(int fd,
444 struct in_addr dst,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000445 uint8_t *pim_msg,
Everton Marques871dbcf2009-08-11 15:43:05 -0300446 int pim_msg_size,
447 const char *ifname)
448{
449 ssize_t sent;
450 struct sockaddr_in to;
451 socklen_t tolen;
452
453 if (PIM_DEBUG_PIM_PACKETS) {
454 char dst_str[100];
455 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
456 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
457 __PRETTY_FUNCTION__,
458 dst_str, ifname, pim_msg_size,
459 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg));
460 }
461
462#if 0
463 memset(&to, 0, sizeof(to));
464#endif
465 to.sin_family = AF_INET;
466 to.sin_addr = dst;
467#if 0
468 to.sin_port = htons(0);
469#endif
470 tolen = sizeof(to);
471
Everton Marques62738042009-11-18 10:44:13 -0200472 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
473 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
474 }
475
David Lampartera2c7f4b2015-03-03 21:03:52 +0100476 sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT,
477 (struct sockaddr *)&to, tolen);
Everton Marques871dbcf2009-08-11 15:43:05 -0300478 if (sent != (ssize_t) pim_msg_size) {
479 int e = errno;
480 char dst_str[100];
481 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
482 if (sent < 0) {
483 zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
484 __PRETTY_FUNCTION__,
485 dst_str, ifname, fd, pim_msg_size,
Everton Marquese96f0af2009-08-11 15:48:02 -0300486 e, safe_strerror(e));
Everton Marques871dbcf2009-08-11 15:43:05 -0300487 }
488 else {
David Lamparter5c697982012-02-16 04:47:56 +0100489 zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
Everton Marques871dbcf2009-08-11 15:43:05 -0300490 __PRETTY_FUNCTION__,
491 dst_str, ifname, fd,
492 pim_msg_size, sent);
493 }
494 return -1;
495 }
496
497 return 0;
498}
499
500static int hello_send(struct interface *ifp,
501 uint16_t holdtime)
502{
David Lamparterf8cfeb22012-02-16 04:31:08 +0000503 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
Everton Marques871dbcf2009-08-11 15:43:05 -0300504 struct pim_interface *pim_ifp;
505 int pim_tlv_size;
506 int pim_msg_size;
507
508 pim_ifp = ifp->info;
509
Balaji.Ged14fa02014-10-08 01:11:31 -0300510 if (PIM_DEBUG_PIM_PACKETS || PIM_DEBUG_PIM_HELLO) {
Everton Marques871dbcf2009-08-11 15:43:05 -0300511 char dst_str[100];
512 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str));
513 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",
514 __PRETTY_FUNCTION__,
515 dst_str, ifp->name,
516 holdtime,
517 pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec,
518 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
519 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
520 listcount(ifp->connected));
521 }
522
523 pim_tlv_size = pim_hello_build_tlv(ifp->name,
524 pim_msg + PIM_PIM_MIN_LEN,
525 sizeof(pim_msg) - PIM_PIM_MIN_LEN,
526 holdtime,
527 pim_ifp->pim_dr_priority,
528 pim_ifp->pim_generation_id,
529 pim_ifp->pim_propagation_delay_msec,
530 pim_ifp->pim_override_interval_msec,
531 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
532 ifp->connected);
533 if (pim_tlv_size < 0) {
534 return -1;
535 }
536
537 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
538
539 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
540 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
541
542 pim_msg_build_header(pim_msg, pim_msg_size,
543 PIM_MSG_TYPE_HELLO);
544
545 if (pim_msg_send(pim_ifp->pim_sock_fd,
546 qpim_all_pim_routers_addr,
547 pim_msg,
548 pim_msg_size,
549 ifp->name)) {
550 zlog_warn("%s: could not send PIM message on interface %s",
551 __PRETTY_FUNCTION__, ifp->name);
552 return -2;
553 }
554
555 return 0;
556}
557
558static int pim_hello_send(struct interface *ifp,
559 uint16_t holdtime)
560{
561 struct pim_interface *pim_ifp;
562
563 zassert(ifp);
564 pim_ifp = ifp->info;
565 zassert(pim_ifp);
566
567 if (hello_send(ifp, holdtime)) {
568 ++pim_ifp->pim_ifstat_hello_sendfail;
569
570 zlog_warn("Could not send PIM hello on interface %s",
571 ifp->name);
572 return -1;
573 }
574
575 ++pim_ifp->pim_ifstat_hello_sent;
576
577 return 0;
578}
579
580static void hello_resched(struct interface *ifp)
581{
582 struct pim_interface *pim_ifp;
583
584 zassert(ifp);
585 pim_ifp = ifp->info;
586 zassert(pim_ifp);
587
588 if (PIM_DEBUG_PIM_TRACE) {
589 zlog_debug("Rescheduling %d sec hello on interface %s",
590 pim_ifp->pim_hello_period, ifp->name);
591 }
592 THREAD_OFF(pim_ifp->t_pim_hello_timer);
593 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
594 on_pim_hello_send,
595 ifp, pim_ifp->pim_hello_period);
596}
597
598/*
599 Periodic hello timer
600 */
601static int on_pim_hello_send(struct thread *t)
602{
603 struct pim_interface *pim_ifp;
604 struct interface *ifp;
605
606 zassert(t);
607 ifp = THREAD_ARG(t);
608 zassert(ifp);
609
610 pim_ifp = ifp->info;
611
612 /*
613 * Schedule next hello
614 */
615 pim_ifp->t_pim_hello_timer = 0;
616 hello_resched(ifp);
617
618 /*
619 * Send hello
620 */
621 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
622}
623
624/*
625 RFC 4601: 4.3.1. Sending Hello Messages
626
627 Thus, if a router needs to send a Join/Prune or Assert message on an
628 interface on which it has not yet sent a Hello message with the
629 currently configured IP address, then it MUST immediately send the
630 relevant Hello message without waiting for the Hello Timer to
631 expire, followed by the Join/Prune or Assert message.
632 */
633void pim_hello_restart_now(struct interface *ifp)
634{
635 struct pim_interface *pim_ifp;
636
637 zassert(ifp);
638 pim_ifp = ifp->info;
639 zassert(pim_ifp);
640
641 /*
642 * Reset next hello timer
643 */
644 hello_resched(ifp);
645
646 /*
647 * Immediately send hello
648 */
649 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
650}
651
652/*
653 RFC 4601: 4.3.1. Sending Hello Messages
654
655 To allow new or rebooting routers to learn of PIM neighbors quickly,
656 when a Hello message is received from a new neighbor, or a Hello
657 message with a new GenID is received from an existing neighbor, a
658 new Hello message should be sent on this interface after a
659 randomized delay between 0 and Triggered_Hello_Delay.
660 */
661void pim_hello_restart_triggered(struct interface *ifp)
662{
663 struct pim_interface *pim_ifp;
664 int triggered_hello_delay_msec;
665 int random_msec;
666
667 zassert(ifp);
668 pim_ifp = ifp->info;
669 zassert(pim_ifp);
670
671 triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
672
673 if (pim_ifp->t_pim_hello_timer) {
674 long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
675 if (remain_msec <= triggered_hello_delay_msec) {
676 /* Rescheduling hello would increase the delay, then it's faster
677 to just wait for the scheduled periodic hello. */
678 return;
679 }
680
681 THREAD_OFF(pim_ifp->t_pim_hello_timer);
682 pim_ifp->t_pim_hello_timer = 0;
683 }
684 zassert(!pim_ifp->t_pim_hello_timer);
685
Donald Sharp77162682015-06-19 19:26:18 -0400686 random_msec = random() % (triggered_hello_delay_msec + 1);
Everton Marques871dbcf2009-08-11 15:43:05 -0300687
688 if (PIM_DEBUG_PIM_EVENTS) {
689 zlog_debug("Scheduling %d msec triggered hello on interface %s",
690 random_msec, ifp->name);
691 }
692
693 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
694 on_pim_hello_send,
Leonard Herve236b0152009-08-11 15:51:52 -0300695 ifp, random_msec);
Everton Marques871dbcf2009-08-11 15:43:05 -0300696}
697
698int pim_sock_add(struct interface *ifp)
699{
700 struct pim_interface *pim_ifp;
701 struct in_addr ifaddr;
Donald Sharpa031c4d2015-07-02 13:22:49 -0400702 uint32_t old_genid;
Everton Marques871dbcf2009-08-11 15:43:05 -0300703
704 pim_ifp = ifp->info;
705 zassert(pim_ifp);
706
707 if (pim_ifp->pim_sock_fd >= 0) {
708 zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
709 pim_ifp->pim_sock_fd, ifp->name);
710 return -1;
711 }
712
713 ifaddr = pim_ifp->primary_address;
714
715 pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
716 if (pim_ifp->pim_sock_fd < 0) {
717 zlog_warn("Could not open PIM socket on interface %s",
718 ifp->name);
719 return -2;
720 }
721
722 pim_ifp->t_pim_sock_read = 0;
723 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
724
Donald Sharpa031c4d2015-07-02 13:22:49 -0400725 /*
726 * Just ensure that the new generation id
727 * actually chooses something different.
728 * Actually ran across a case where this
729 * happened, pre-switch to random().
730 * While this is unlikely to happen now
731 * let's make sure it doesn't.
732 */
733 old_genid = pim_ifp->pim_generation_id;
734
735 while (old_genid == pim_ifp->pim_generation_id)
736 pim_ifp->pim_generation_id = random();
Everton Marques871dbcf2009-08-11 15:43:05 -0300737
Everton Marques85385f72015-01-19 18:25:45 -0200738 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
739 ifp->name, ifp->ifindex);
Everton Marques871dbcf2009-08-11 15:43:05 -0300740
741 /*
742 * Start receiving PIM messages
743 */
744 pim_sock_read_on(ifp);
745
746 /*
747 * Start sending PIM hello's
748 */
749 pim_hello_restart_triggered(ifp);
750
751 return 0;
752}