blob: fb6c3acb94f7e806d7d5673cd7886b969a6db506 [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"
42#include "pim_rand.h"
43
44static int on_pim_hello_send(struct thread *t);
45static int pim_hello_send(struct interface *ifp,
46 uint16_t holdtime);
47
48static void sock_close(struct interface *ifp)
49{
50 struct pim_interface *pim_ifp = ifp->info;
51
52 if (PIM_DEBUG_PIM_TRACE) {
53 if (pim_ifp->t_pim_sock_read) {
54 zlog_debug("Cancelling READ event for PIM socket fd=%d on interface %s",
55 pim_ifp->pim_sock_fd,
56 ifp->name);
57 }
58 }
59 THREAD_OFF(pim_ifp->t_pim_sock_read);
60
61 if (PIM_DEBUG_PIM_TRACE) {
62 if (pim_ifp->t_pim_hello_timer) {
63 zlog_debug("Cancelling PIM hello timer for interface %s",
64 ifp->name);
65 }
66 }
67 THREAD_OFF(pim_ifp->t_pim_hello_timer);
68
69 if (PIM_DEBUG_PIM_TRACE) {
70 zlog_debug("Deleting PIM socket fd=%d on interface %s",
71 pim_ifp->pim_sock_fd, ifp->name);
72 }
73
74 if (close(pim_ifp->pim_sock_fd)) {
75 zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
76 pim_ifp->pim_sock_fd, ifp->name,
Everton Marquese96f0af2009-08-11 15:48:02 -030077 errno, safe_strerror(errno));
Everton Marques871dbcf2009-08-11 15:43:05 -030078 }
79
80 pim_ifp->pim_sock_fd = -1;
81 pim_ifp->pim_sock_creation = 0;
82
83 zassert(pim_ifp->pim_sock_fd < 0);
84 zassert(!pim_ifp->t_pim_sock_read);
85 zassert(!pim_ifp->t_pim_hello_timer);
86 zassert(!pim_ifp->pim_sock_creation);
87}
88
89void pim_sock_delete(struct interface *ifp, const char *delete_message)
90{
91 zlog_info("PIM INTERFACE DOWN: on interface %s: %s",
92 ifp->name, delete_message);
93
Everton Marquese96f0af2009-08-11 15:48:02 -030094 if (!ifp->info) {
95 zlog_err("%s: %s: but PIM not enabled on interface %s (!)",
96 __PRETTY_FUNCTION__, delete_message, ifp->name);
97 return;
98 }
99
Everton Marques871dbcf2009-08-11 15:43:05 -0300100 /*
101 RFC 4601: 4.3.1. Sending Hello Messages
102
103 Before an interface goes down or changes primary IP address, a Hello
104 message with a zero HoldTime should be sent immediately (with the
105 old IP address if the IP address changed).
106 */
107 pim_hello_send(ifp, 0 /* zero-sec holdtime */);
108
109 pim_neighbor_delete_all(ifp, delete_message);
110
111 sock_close(ifp);
112}
113
David Lamparterf8cfeb22012-02-16 04:31:08 +0000114int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
Everton Marques871dbcf2009-08-11 15:43:05 -0300115{
116 struct ip *ip_hdr;
117 size_t ip_hlen; /* ip header length in bytes */
118 char src_str[100];
119 char dst_str[100];
David Lamparterf8cfeb22012-02-16 04:31:08 +0000120 uint8_t *pim_msg;
Everton Marques871dbcf2009-08-11 15:43:05 -0300121 int pim_msg_len;
122 uint8_t pim_version;
123 uint8_t pim_type;
124 uint16_t pim_checksum; /* received checksum */
125 uint16_t checksum; /* computed checksum */
126 struct pim_neighbor *neigh;
127
128 if (!ifp->info) {
129 zlog_warn("%s: PIM not enabled on interface %s",
130 __PRETTY_FUNCTION__, ifp->name);
131 return -1;
132 }
133
134 if (len < sizeof(*ip_hdr)) {
David Lamparter5c697982012-02-16 04:47:56 +0100135 zlog_warn("PIM packet size=%zu shorter than minimum=%zu",
Everton Marques871dbcf2009-08-11 15:43:05 -0300136 len, sizeof(*ip_hdr));
137 return -1;
138 }
139
140 ip_hdr = (struct ip *) buf;
141
142 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
143 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str, sizeof(dst_str));
144
145 ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
146
147 if (PIM_DEBUG_PIM_PACKETS) {
David Lamparter5c697982012-02-16 04:47:56 +0100148 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 -0300149 src_str, dst_str, ifp->name, len, ip_hlen, ip_hdr->ip_p);
150 }
151
152 if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) {
153 zlog_warn("IP packet protocol=%d is not PIM=%d",
154 ip_hdr->ip_p, PIM_IP_PROTO_PIM);
155 return -1;
156 }
157
158 if (ip_hlen < PIM_IP_HEADER_MIN_LEN) {
David Lamparter5c697982012-02-16 04:47:56 +0100159 zlog_warn("IP packet header size=%zu shorter than minimum=%d",
Everton Marques871dbcf2009-08-11 15:43:05 -0300160 ip_hlen, PIM_IP_HEADER_MIN_LEN);
161 return -1;
162 }
163 if (ip_hlen > PIM_IP_HEADER_MAX_LEN) {
David Lamparter5c697982012-02-16 04:47:56 +0100164 zlog_warn("IP packet header size=%zu greater than maximum=%d",
Everton Marques871dbcf2009-08-11 15:43:05 -0300165 ip_hlen, PIM_IP_HEADER_MAX_LEN);
166 return -1;
167 }
168
169 pim_msg = buf + ip_hlen;
170 pim_msg_len = len - ip_hlen;
171
Everton Marques62738042009-11-18 10:44:13 -0200172 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
173 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
174 }
175
Everton Marques871dbcf2009-08-11 15:43:05 -0300176 if (pim_msg_len < PIM_PIM_MIN_LEN) {
177 zlog_warn("PIM message size=%d shorter than minimum=%d",
178 pim_msg_len, PIM_PIM_MIN_LEN);
179 return -1;
180 }
181
182 pim_version = PIM_MSG_HDR_GET_VERSION(pim_msg);
183 pim_type = PIM_MSG_HDR_GET_TYPE(pim_msg);
184
185 if (pim_version != PIM_PROTO_VERSION) {
186 zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d",
187 ifp->name, pim_version);
188 return -1;
189 }
190
191 /* save received checksum */
192 pim_checksum = PIM_MSG_HDR_GET_CHECKSUM(pim_msg);
193
194 /* for computing checksum */
195 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0;
196
Everton Marques93911262014-09-18 11:10:58 -0300197 checksum = in_cksum(pim_msg, pim_msg_len);
Everton Marques871dbcf2009-08-11 15:43:05 -0300198 if (checksum != pim_checksum) {
199 zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
200 ifp->name, pim_checksum, checksum);
201 return -1;
202 }
203
204 if (PIM_DEBUG_PIM_PACKETS) {
205 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",
206 src_str, dst_str, ifp->name, ip_hdr->ip_ttl,
207 pim_version, pim_type, pim_msg_len, checksum);
208 }
209
210 if (pim_type == PIM_MSG_TYPE_HELLO) {
Everton Marques777fe1f2014-02-14 14:16:07 -0200211 int result = pim_hello_recv(ifp,
212 ip_hdr->ip_src,
213 pim_msg + PIM_MSG_HEADER_LEN,
214 pim_msg_len - PIM_MSG_HEADER_LEN);
215 if (!result) {
216 pim_if_dr_election(ifp); /* PIM Hello message is received */
217 }
218 return result;
Everton Marques871dbcf2009-08-11 15:43:05 -0300219 }
220
221 neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
222 if (!neigh) {
223 zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
224 __FILE__, __PRETTY_FUNCTION__,
225 pim_type, src_str, ifp->name);
226 return -1;
227 }
228
229 switch (pim_type) {
230 case PIM_MSG_TYPE_JOIN_PRUNE:
231 return pim_joinprune_recv(ifp, neigh,
232 ip_hdr->ip_src,
233 pim_msg + PIM_MSG_HEADER_LEN,
234 pim_msg_len - PIM_MSG_HEADER_LEN);
235 case PIM_MSG_TYPE_ASSERT:
236 return pim_assert_recv(ifp, neigh,
237 ip_hdr->ip_src,
238 pim_msg + PIM_MSG_HEADER_LEN,
239 pim_msg_len - PIM_MSG_HEADER_LEN);
240 default:
241 zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s",
242 __FILE__, __PRETTY_FUNCTION__,
243 pim_type, src_str, ifp->name);
244 }
245
246 return -1;
247}
248
249static void pim_sock_read_on(struct interface *ifp);
250
251static int pim_sock_read(struct thread *t)
252{
253 struct interface *ifp;
254 struct pim_interface *pim_ifp;
255 int fd;
256 struct sockaddr_in from;
257 struct sockaddr_in to;
258 socklen_t fromlen = sizeof(from);
259 socklen_t tolen = sizeof(to);
David Lamparterf8cfeb22012-02-16 04:31:08 +0000260 uint8_t buf[PIM_PIM_BUFSIZE_READ];
Everton Marques871dbcf2009-08-11 15:43:05 -0300261 int len;
262 int ifindex = -1;
263 int result = -1; /* defaults to bad */
264
265 zassert(t);
266
267 ifp = THREAD_ARG(t);
268 zassert(ifp);
269
270 fd = THREAD_FD(t);
271
272 pim_ifp = ifp->info;
273 zassert(pim_ifp);
274
275 zassert(fd == pim_ifp->pim_sock_fd);
276
277 len = pim_socket_recvfromto(fd, buf, sizeof(buf),
278 &from, &fromlen,
279 &to, &tolen,
280 &ifindex);
281 if (len < 0) {
282 zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s",
Everton Marquese96f0af2009-08-11 15:48:02 -0300283 fd, errno, safe_strerror(errno));
Everton Marques871dbcf2009-08-11 15:43:05 -0300284 goto done;
285 }
286
287 if (PIM_DEBUG_PIM_PACKETS) {
288 char from_str[100];
289 char to_str[100];
290
291 if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str)))
292 sprintf(from_str, "<from?>");
293 if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str)))
294 sprintf(to_str, "<to?>");
295
296 zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)",
297 len, from_str, to_str, fd, ifindex, ifp->ifindex);
298 }
299
Everton Marques62738042009-11-18 10:44:13 -0200300 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
301 pim_pkt_dump(__PRETTY_FUNCTION__, buf, len);
302 }
303
Everton Marques871dbcf2009-08-11 15:43:05 -0300304#ifdef PIM_CHECK_RECV_IFINDEX_SANITY
305 /* ifindex sanity check */
306 if (ifindex != (int) ifp->ifindex) {
307 char from_str[100];
308 char to_str[100];
309 struct interface *recv_ifp;
310
311 if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
312 sprintf(from_str, "<from?>");
313 if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
314 sprintf(to_str, "<to?>");
315
316 recv_ifp = if_lookup_by_index(ifindex);
317 if (recv_ifp) {
318 zassert(ifindex == (int) recv_ifp->ifindex);
319 }
320
321#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
322 zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
323 from_str, to_str, fd,
324 ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
325 ifp->ifindex, ifp->name);
326#endif
327 goto done;
328 }
329#endif
330
Everton Marques777fe1f2014-02-14 14:16:07 -0200331 int fail = pim_pim_packet(ifp, buf, len);
332 if (fail) {
333 zlog_warn("%s: pim_pim_packet() return=%d",
334 __PRETTY_FUNCTION__, fail);
Everton Marques871dbcf2009-08-11 15:43:05 -0300335 goto done;
336 }
337
338 result = 0; /* good */
339
340 done:
341 pim_sock_read_on(ifp);
342
343 if (result) {
344 ++pim_ifp->pim_ifstat_hello_recvfail;
345 }
346
347 return result;
348}
349
350static void pim_sock_read_on(struct interface *ifp)
351{
352 struct pim_interface *pim_ifp;
353
354 zassert(ifp);
355 zassert(ifp->info);
356
357 pim_ifp = ifp->info;
358
359 if (PIM_DEBUG_PIM_TRACE) {
360 zlog_debug("Scheduling READ event on PIM socket fd=%d",
361 pim_ifp->pim_sock_fd);
362 }
363 pim_ifp->t_pim_sock_read = 0;
364 zassert(!pim_ifp->t_pim_sock_read);
365 THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
366 pim_ifp->pim_sock_fd);
367}
368
369static int pim_sock_open(struct in_addr ifaddr, int ifindex)
370{
371 int fd;
372
373 fd = pim_socket_mcast(IPPROTO_PIM, ifaddr, 0 /* loop=false */);
374 if (fd < 0)
375 return -1;
376
377 if (pim_socket_join(fd, qpim_all_pim_routers_addr, ifaddr, ifindex)) {
378 return -2;
379 }
380
381 return fd;
382}
383
384void pim_ifstat_reset(struct interface *ifp)
385{
386 struct pim_interface *pim_ifp;
387
388 zassert(ifp);
389
390 pim_ifp = ifp->info;
391 if (!pim_ifp) {
392 return;
393 }
394
395 pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
396 pim_ifp->pim_ifstat_hello_sent = 0;
397 pim_ifp->pim_ifstat_hello_sendfail = 0;
398 pim_ifp->pim_ifstat_hello_recv = 0;
399 pim_ifp->pim_ifstat_hello_recvfail = 0;
400}
401
402void pim_sock_reset(struct interface *ifp)
403{
404 struct pim_interface *pim_ifp;
405
406 zassert(ifp);
407 zassert(ifp->info);
408
409 pim_ifp = ifp->info;
410
411 pim_ifp->primary_address = pim_find_primary_addr(ifp);
412
413 pim_ifp->pim_sock_fd = -1;
414 pim_ifp->pim_sock_creation = 0;
415 pim_ifp->t_pim_sock_read = 0;
416
417 pim_ifp->t_pim_hello_timer = 0;
418 pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
419 pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
420 pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
421 pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
422 pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
423 pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
424 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
425 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
426 }
427 else {
428 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
429 }
430
431 /* neighbors without lan_delay */
432 pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
433 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
434 pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
435
436 /* DR Election */
437 pim_ifp->pim_dr_election_last = 0; /* timestamp */
438 pim_ifp->pim_dr_election_count = 0;
Everton Marques777fe1f2014-02-14 14:16:07 -0200439 pim_ifp->pim_dr_election_changes = 0;
Everton Marques871dbcf2009-08-11 15:43:05 -0300440 pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */
441 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
442
443 pim_ifstat_reset(ifp);
444}
445
446int pim_msg_send(int fd,
447 struct in_addr dst,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000448 uint8_t *pim_msg,
Everton Marques871dbcf2009-08-11 15:43:05 -0300449 int pim_msg_size,
450 const char *ifname)
451{
452 ssize_t sent;
453 struct sockaddr_in to;
454 socklen_t tolen;
455
456 if (PIM_DEBUG_PIM_PACKETS) {
457 char dst_str[100];
458 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
459 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
460 __PRETTY_FUNCTION__,
461 dst_str, ifname, pim_msg_size,
462 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg));
463 }
464
465#if 0
466 memset(&to, 0, sizeof(to));
467#endif
468 to.sin_family = AF_INET;
469 to.sin_addr = dst;
470#if 0
471 to.sin_port = htons(0);
472#endif
473 tolen = sizeof(to);
474
Everton Marques62738042009-11-18 10:44:13 -0200475 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
476 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
477 }
478
Everton Marques871dbcf2009-08-11 15:43:05 -0300479 sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT, &to, tolen);
480 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
512 if (PIM_DEBUG_PIM_PACKETS) {
513 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
688 random_msec = pim_rand_next(0, triggered_hello_delay_msec);
689
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
726 pim_ifp->pim_generation_id = pim_rand() & (int64_t) 0xFFFFFFFF;
727
728 zlog_info("PIM INTERFACE UP: on interface %s",
729 ifp->name);
730
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}