blob: 409972d4b3be496216f80442d7198cbd3fe9108c [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);
214 if (!result) {
215 pim_if_dr_election(ifp); /* PIM Hello message is received */
216 }
217 return result;
Everton Marques871dbcf2009-08-11 15:43:05 -0300218 }
219
220 neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
221 if (!neigh) {
222 zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
223 __FILE__, __PRETTY_FUNCTION__,
224 pim_type, src_str, ifp->name);
225 return -1;
226 }
227
228 switch (pim_type) {
229 case PIM_MSG_TYPE_JOIN_PRUNE:
230 return pim_joinprune_recv(ifp, neigh,
231 ip_hdr->ip_src,
232 pim_msg + PIM_MSG_HEADER_LEN,
233 pim_msg_len - PIM_MSG_HEADER_LEN);
234 case PIM_MSG_TYPE_ASSERT:
235 return pim_assert_recv(ifp, neigh,
236 ip_hdr->ip_src,
237 pim_msg + PIM_MSG_HEADER_LEN,
238 pim_msg_len - PIM_MSG_HEADER_LEN);
239 default:
240 zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s",
241 __FILE__, __PRETTY_FUNCTION__,
242 pim_type, src_str, ifp->name);
243 }
244
245 return -1;
246}
247
248static void pim_sock_read_on(struct interface *ifp);
249
250static int pim_sock_read(struct thread *t)
251{
252 struct interface *ifp;
253 struct pim_interface *pim_ifp;
254 int fd;
255 struct sockaddr_in from;
256 struct sockaddr_in to;
257 socklen_t fromlen = sizeof(from);
258 socklen_t tolen = sizeof(to);
David Lamparterf8cfeb22012-02-16 04:31:08 +0000259 uint8_t buf[PIM_PIM_BUFSIZE_READ];
Everton Marques871dbcf2009-08-11 15:43:05 -0300260 int len;
261 int ifindex = -1;
262 int result = -1; /* defaults to bad */
263
264 zassert(t);
265
266 ifp = THREAD_ARG(t);
267 zassert(ifp);
268
269 fd = THREAD_FD(t);
270
271 pim_ifp = ifp->info;
272 zassert(pim_ifp);
273
274 zassert(fd == pim_ifp->pim_sock_fd);
275
276 len = pim_socket_recvfromto(fd, buf, sizeof(buf),
277 &from, &fromlen,
278 &to, &tolen,
279 &ifindex);
280 if (len < 0) {
281 zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s",
Everton Marquese96f0af2009-08-11 15:48:02 -0300282 fd, errno, safe_strerror(errno));
Everton Marques871dbcf2009-08-11 15:43:05 -0300283 goto done;
284 }
285
286 if (PIM_DEBUG_PIM_PACKETS) {
287 char from_str[100];
288 char to_str[100];
289
290 if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str)))
291 sprintf(from_str, "<from?>");
292 if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str)))
293 sprintf(to_str, "<to?>");
294
295 zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)",
296 len, from_str, to_str, fd, ifindex, ifp->ifindex);
297 }
298
Everton Marques62738042009-11-18 10:44:13 -0200299 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
300 pim_pkt_dump(__PRETTY_FUNCTION__, buf, len);
301 }
302
Everton Marques871dbcf2009-08-11 15:43:05 -0300303#ifdef PIM_CHECK_RECV_IFINDEX_SANITY
304 /* ifindex sanity check */
305 if (ifindex != (int) ifp->ifindex) {
306 char from_str[100];
307 char to_str[100];
308 struct interface *recv_ifp;
309
310 if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
311 sprintf(from_str, "<from?>");
312 if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
313 sprintf(to_str, "<to?>");
314
315 recv_ifp = if_lookup_by_index(ifindex);
316 if (recv_ifp) {
317 zassert(ifindex == (int) recv_ifp->ifindex);
318 }
319
320#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
321 zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
322 from_str, to_str, fd,
323 ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
324 ifp->ifindex, ifp->name);
325#endif
326 goto done;
327 }
328#endif
329
Everton Marques777fe1f2014-02-14 14:16:07 -0200330 int fail = pim_pim_packet(ifp, buf, len);
331 if (fail) {
332 zlog_warn("%s: pim_pim_packet() return=%d",
333 __PRETTY_FUNCTION__, fail);
Everton Marques871dbcf2009-08-11 15:43:05 -0300334 goto done;
335 }
336
337 result = 0; /* good */
338
339 done:
340 pim_sock_read_on(ifp);
341
342 if (result) {
343 ++pim_ifp->pim_ifstat_hello_recvfail;
344 }
345
346 return result;
347}
348
349static void pim_sock_read_on(struct interface *ifp)
350{
351 struct pim_interface *pim_ifp;
352
353 zassert(ifp);
354 zassert(ifp->info);
355
356 pim_ifp = ifp->info;
357
358 if (PIM_DEBUG_PIM_TRACE) {
359 zlog_debug("Scheduling READ event on PIM socket fd=%d",
360 pim_ifp->pim_sock_fd);
361 }
362 pim_ifp->t_pim_sock_read = 0;
363 zassert(!pim_ifp->t_pim_sock_read);
364 THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
365 pim_ifp->pim_sock_fd);
366}
367
368static int pim_sock_open(struct in_addr ifaddr, int ifindex)
369{
370 int fd;
371
372 fd = pim_socket_mcast(IPPROTO_PIM, ifaddr, 0 /* loop=false */);
373 if (fd < 0)
374 return -1;
375
376 if (pim_socket_join(fd, qpim_all_pim_routers_addr, ifaddr, ifindex)) {
377 return -2;
378 }
379
380 return fd;
381}
382
383void pim_ifstat_reset(struct interface *ifp)
384{
385 struct pim_interface *pim_ifp;
386
387 zassert(ifp);
388
389 pim_ifp = ifp->info;
390 if (!pim_ifp) {
391 return;
392 }
393
394 pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
395 pim_ifp->pim_ifstat_hello_sent = 0;
396 pim_ifp->pim_ifstat_hello_sendfail = 0;
397 pim_ifp->pim_ifstat_hello_recv = 0;
398 pim_ifp->pim_ifstat_hello_recvfail = 0;
399}
400
401void pim_sock_reset(struct interface *ifp)
402{
403 struct pim_interface *pim_ifp;
404
405 zassert(ifp);
406 zassert(ifp->info);
407
408 pim_ifp = ifp->info;
409
410 pim_ifp->primary_address = pim_find_primary_addr(ifp);
411
412 pim_ifp->pim_sock_fd = -1;
413 pim_ifp->pim_sock_creation = 0;
414 pim_ifp->t_pim_sock_read = 0;
415
416 pim_ifp->t_pim_hello_timer = 0;
417 pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
418 pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
419 pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
420 pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
421 pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
422 pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
423 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
424 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
425 }
426 else {
427 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
428 }
429
430 /* neighbors without lan_delay */
431 pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
432 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
433 pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
434
435 /* DR Election */
436 pim_ifp->pim_dr_election_last = 0; /* timestamp */
437 pim_ifp->pim_dr_election_count = 0;
Everton Marques777fe1f2014-02-14 14:16:07 -0200438 pim_ifp->pim_dr_election_changes = 0;
Everton Marques871dbcf2009-08-11 15:43:05 -0300439 pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */
440 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
441
442 pim_ifstat_reset(ifp);
443}
444
445int pim_msg_send(int fd,
446 struct in_addr dst,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000447 uint8_t *pim_msg,
Everton Marques871dbcf2009-08-11 15:43:05 -0300448 int pim_msg_size,
449 const char *ifname)
450{
451 ssize_t sent;
452 struct sockaddr_in to;
453 socklen_t tolen;
454
455 if (PIM_DEBUG_PIM_PACKETS) {
456 char dst_str[100];
457 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
458 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
459 __PRETTY_FUNCTION__,
460 dst_str, ifname, pim_msg_size,
461 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg));
462 }
463
464#if 0
465 memset(&to, 0, sizeof(to));
466#endif
467 to.sin_family = AF_INET;
468 to.sin_addr = dst;
469#if 0
470 to.sin_port = htons(0);
471#endif
472 tolen = sizeof(to);
473
Everton Marques62738042009-11-18 10:44:13 -0200474 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
475 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
476 }
477
David Lampartera2c7f4b2015-03-03 21:03:52 +0100478 sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT,
479 (struct sockaddr *)&to, tolen);
Everton Marques871dbcf2009-08-11 15:43:05 -0300480 if (sent != (ssize_t) pim_msg_size) {
481 int e = errno;
482 char dst_str[100];
483 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
484 if (sent < 0) {
485 zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
486 __PRETTY_FUNCTION__,
487 dst_str, ifname, fd, pim_msg_size,
Everton Marquese96f0af2009-08-11 15:48:02 -0300488 e, safe_strerror(e));
Everton Marques871dbcf2009-08-11 15:43:05 -0300489 }
490 else {
David Lamparter5c697982012-02-16 04:47:56 +0100491 zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
Everton Marques871dbcf2009-08-11 15:43:05 -0300492 __PRETTY_FUNCTION__,
493 dst_str, ifname, fd,
494 pim_msg_size, sent);
495 }
496 return -1;
497 }
498
499 return 0;
500}
501
502static int hello_send(struct interface *ifp,
503 uint16_t holdtime)
504{
David Lamparterf8cfeb22012-02-16 04:31:08 +0000505 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
Everton Marques871dbcf2009-08-11 15:43:05 -0300506 struct pim_interface *pim_ifp;
507 int pim_tlv_size;
508 int pim_msg_size;
509
510 pim_ifp = ifp->info;
511
Balaji.Ged14fa02014-10-08 01:11:31 -0300512 if (PIM_DEBUG_PIM_PACKETS || PIM_DEBUG_PIM_HELLO) {
Everton Marques871dbcf2009-08-11 15:43:05 -0300513 char dst_str[100];
514 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str));
515 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",
516 __PRETTY_FUNCTION__,
517 dst_str, ifp->name,
518 holdtime,
519 pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec,
520 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
521 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
522 listcount(ifp->connected));
523 }
524
525 pim_tlv_size = pim_hello_build_tlv(ifp->name,
526 pim_msg + PIM_PIM_MIN_LEN,
527 sizeof(pim_msg) - PIM_PIM_MIN_LEN,
528 holdtime,
529 pim_ifp->pim_dr_priority,
530 pim_ifp->pim_generation_id,
531 pim_ifp->pim_propagation_delay_msec,
532 pim_ifp->pim_override_interval_msec,
533 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
534 ifp->connected);
535 if (pim_tlv_size < 0) {
536 return -1;
537 }
538
539 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
540
541 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
542 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
543
544 pim_msg_build_header(pim_msg, pim_msg_size,
545 PIM_MSG_TYPE_HELLO);
546
547 if (pim_msg_send(pim_ifp->pim_sock_fd,
548 qpim_all_pim_routers_addr,
549 pim_msg,
550 pim_msg_size,
551 ifp->name)) {
552 zlog_warn("%s: could not send PIM message on interface %s",
553 __PRETTY_FUNCTION__, ifp->name);
554 return -2;
555 }
556
557 return 0;
558}
559
560static int pim_hello_send(struct interface *ifp,
561 uint16_t holdtime)
562{
563 struct pim_interface *pim_ifp;
564
565 zassert(ifp);
566 pim_ifp = ifp->info;
567 zassert(pim_ifp);
568
569 if (hello_send(ifp, holdtime)) {
570 ++pim_ifp->pim_ifstat_hello_sendfail;
571
572 zlog_warn("Could not send PIM hello on interface %s",
573 ifp->name);
574 return -1;
575 }
576
577 ++pim_ifp->pim_ifstat_hello_sent;
578
579 return 0;
580}
581
582static void hello_resched(struct interface *ifp)
583{
584 struct pim_interface *pim_ifp;
585
586 zassert(ifp);
587 pim_ifp = ifp->info;
588 zassert(pim_ifp);
589
590 if (PIM_DEBUG_PIM_TRACE) {
591 zlog_debug("Rescheduling %d sec hello on interface %s",
592 pim_ifp->pim_hello_period, ifp->name);
593 }
594 THREAD_OFF(pim_ifp->t_pim_hello_timer);
595 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
596 on_pim_hello_send,
597 ifp, pim_ifp->pim_hello_period);
598}
599
600/*
601 Periodic hello timer
602 */
603static int on_pim_hello_send(struct thread *t)
604{
605 struct pim_interface *pim_ifp;
606 struct interface *ifp;
607
608 zassert(t);
609 ifp = THREAD_ARG(t);
610 zassert(ifp);
611
612 pim_ifp = ifp->info;
613
614 /*
615 * Schedule next hello
616 */
617 pim_ifp->t_pim_hello_timer = 0;
618 hello_resched(ifp);
619
620 /*
621 * Send hello
622 */
623 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
624}
625
626/*
627 RFC 4601: 4.3.1. Sending Hello Messages
628
629 Thus, if a router needs to send a Join/Prune or Assert message on an
630 interface on which it has not yet sent a Hello message with the
631 currently configured IP address, then it MUST immediately send the
632 relevant Hello message without waiting for the Hello Timer to
633 expire, followed by the Join/Prune or Assert message.
634 */
635void pim_hello_restart_now(struct interface *ifp)
636{
637 struct pim_interface *pim_ifp;
638
639 zassert(ifp);
640 pim_ifp = ifp->info;
641 zassert(pim_ifp);
642
643 /*
644 * Reset next hello timer
645 */
646 hello_resched(ifp);
647
648 /*
649 * Immediately send hello
650 */
651 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
652}
653
654/*
655 RFC 4601: 4.3.1. Sending Hello Messages
656
657 To allow new or rebooting routers to learn of PIM neighbors quickly,
658 when a Hello message is received from a new neighbor, or a Hello
659 message with a new GenID is received from an existing neighbor, a
660 new Hello message should be sent on this interface after a
661 randomized delay between 0 and Triggered_Hello_Delay.
662 */
663void pim_hello_restart_triggered(struct interface *ifp)
664{
665 struct pim_interface *pim_ifp;
666 int triggered_hello_delay_msec;
667 int random_msec;
668
669 zassert(ifp);
670 pim_ifp = ifp->info;
671 zassert(pim_ifp);
672
673 triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
674
675 if (pim_ifp->t_pim_hello_timer) {
676 long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
677 if (remain_msec <= triggered_hello_delay_msec) {
678 /* Rescheduling hello would increase the delay, then it's faster
679 to just wait for the scheduled periodic hello. */
680 return;
681 }
682
683 THREAD_OFF(pim_ifp->t_pim_hello_timer);
684 pim_ifp->t_pim_hello_timer = 0;
685 }
686 zassert(!pim_ifp->t_pim_hello_timer);
687
Donald Sharp77162682015-06-19 19:26:18 -0400688 random_msec = random() % (triggered_hello_delay_msec + 1);
Everton Marques871dbcf2009-08-11 15:43:05 -0300689
690 if (PIM_DEBUG_PIM_EVENTS) {
691 zlog_debug("Scheduling %d msec triggered hello on interface %s",
692 random_msec, ifp->name);
693 }
694
695 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
696 on_pim_hello_send,
Leonard Herve236b0152009-08-11 15:51:52 -0300697 ifp, random_msec);
Everton Marques871dbcf2009-08-11 15:43:05 -0300698}
699
700int pim_sock_add(struct interface *ifp)
701{
702 struct pim_interface *pim_ifp;
703 struct in_addr ifaddr;
704
705 pim_ifp = ifp->info;
706 zassert(pim_ifp);
707
708 if (pim_ifp->pim_sock_fd >= 0) {
709 zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
710 pim_ifp->pim_sock_fd, ifp->name);
711 return -1;
712 }
713
714 ifaddr = pim_ifp->primary_address;
715
716 pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
717 if (pim_ifp->pim_sock_fd < 0) {
718 zlog_warn("Could not open PIM socket on interface %s",
719 ifp->name);
720 return -2;
721 }
722
723 pim_ifp->t_pim_sock_read = 0;
724 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
725
Donald Sharp77162682015-06-19 19:26:18 -0400726 pim_ifp->pim_generation_id = random();
Everton Marques871dbcf2009-08-11 15:43:05 -0300727
Everton Marques85385f72015-01-19 18:25:45 -0200728 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
729 ifp->name, ifp->ifindex);
Everton Marques871dbcf2009-08-11 15:43:05 -0300730
731 /*
732 * Start receiving PIM messages
733 */
734 pim_sock_read_on(ifp);
735
736 /*
737 * Start sending PIM hello's
738 */
739 pim_hello_restart_triggered(ifp);
740
741 return 0;
742}