blob: 41c26a8883b6af32e706bf19aab0f74f991d8d69 [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)) {
374 return -2;
375 }
376
377 return fd;
378}
379
380void pim_ifstat_reset(struct interface *ifp)
381{
382 struct pim_interface *pim_ifp;
383
384 zassert(ifp);
385
386 pim_ifp = ifp->info;
387 if (!pim_ifp) {
388 return;
389 }
390
391 pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
392 pim_ifp->pim_ifstat_hello_sent = 0;
393 pim_ifp->pim_ifstat_hello_sendfail = 0;
394 pim_ifp->pim_ifstat_hello_recv = 0;
395 pim_ifp->pim_ifstat_hello_recvfail = 0;
396}
397
398void pim_sock_reset(struct interface *ifp)
399{
400 struct pim_interface *pim_ifp;
401
402 zassert(ifp);
403 zassert(ifp->info);
404
405 pim_ifp = ifp->info;
406
407 pim_ifp->primary_address = pim_find_primary_addr(ifp);
408
409 pim_ifp->pim_sock_fd = -1;
410 pim_ifp->pim_sock_creation = 0;
411 pim_ifp->t_pim_sock_read = 0;
412
413 pim_ifp->t_pim_hello_timer = 0;
414 pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
415 pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
416 pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
417 pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
418 pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
419 pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
420 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
421 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
422 }
423 else {
424 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
425 }
426
427 /* neighbors without lan_delay */
428 pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
429 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
430 pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
431
432 /* DR Election */
433 pim_ifp->pim_dr_election_last = 0; /* timestamp */
434 pim_ifp->pim_dr_election_count = 0;
Everton Marques777fe1f2014-02-14 14:16:07 -0200435 pim_ifp->pim_dr_election_changes = 0;
Everton Marques871dbcf2009-08-11 15:43:05 -0300436 pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */
437 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
438
439 pim_ifstat_reset(ifp);
440}
441
442int pim_msg_send(int fd,
443 struct in_addr dst,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000444 uint8_t *pim_msg,
Everton Marques871dbcf2009-08-11 15:43:05 -0300445 int pim_msg_size,
446 const char *ifname)
447{
448 ssize_t sent;
449 struct sockaddr_in to;
450 socklen_t tolen;
451
452 if (PIM_DEBUG_PIM_PACKETS) {
453 char dst_str[100];
454 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
455 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
456 __PRETTY_FUNCTION__,
457 dst_str, ifname, pim_msg_size,
458 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg));
459 }
460
461#if 0
462 memset(&to, 0, sizeof(to));
463#endif
464 to.sin_family = AF_INET;
465 to.sin_addr = dst;
466#if 0
467 to.sin_port = htons(0);
468#endif
469 tolen = sizeof(to);
470
Everton Marques62738042009-11-18 10:44:13 -0200471 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
472 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
473 }
474
David Lampartera2c7f4b2015-03-03 21:03:52 +0100475 sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT,
476 (struct sockaddr *)&to, tolen);
Everton Marques871dbcf2009-08-11 15:43:05 -0300477 if (sent != (ssize_t) pim_msg_size) {
478 int e = errno;
479 char dst_str[100];
480 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
481 if (sent < 0) {
482 zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
483 __PRETTY_FUNCTION__,
484 dst_str, ifname, fd, pim_msg_size,
Everton Marquese96f0af2009-08-11 15:48:02 -0300485 e, safe_strerror(e));
Everton Marques871dbcf2009-08-11 15:43:05 -0300486 }
487 else {
David Lamparter5c697982012-02-16 04:47:56 +0100488 zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
Everton Marques871dbcf2009-08-11 15:43:05 -0300489 __PRETTY_FUNCTION__,
490 dst_str, ifname, fd,
491 pim_msg_size, sent);
492 }
493 return -1;
494 }
495
496 return 0;
497}
498
499static int hello_send(struct interface *ifp,
500 uint16_t holdtime)
501{
David Lamparterf8cfeb22012-02-16 04:31:08 +0000502 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
Everton Marques871dbcf2009-08-11 15:43:05 -0300503 struct pim_interface *pim_ifp;
504 int pim_tlv_size;
505 int pim_msg_size;
506
507 pim_ifp = ifp->info;
508
Balaji.Ged14fa02014-10-08 01:11:31 -0300509 if (PIM_DEBUG_PIM_PACKETS || PIM_DEBUG_PIM_HELLO) {
Everton Marques871dbcf2009-08-11 15:43:05 -0300510 char dst_str[100];
511 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str));
512 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",
513 __PRETTY_FUNCTION__,
514 dst_str, ifp->name,
515 holdtime,
516 pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec,
517 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
518 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
519 listcount(ifp->connected));
520 }
521
522 pim_tlv_size = pim_hello_build_tlv(ifp->name,
523 pim_msg + PIM_PIM_MIN_LEN,
524 sizeof(pim_msg) - PIM_PIM_MIN_LEN,
525 holdtime,
526 pim_ifp->pim_dr_priority,
527 pim_ifp->pim_generation_id,
528 pim_ifp->pim_propagation_delay_msec,
529 pim_ifp->pim_override_interval_msec,
530 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
531 ifp->connected);
532 if (pim_tlv_size < 0) {
533 return -1;
534 }
535
536 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
537
538 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
539 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
540
541 pim_msg_build_header(pim_msg, pim_msg_size,
542 PIM_MSG_TYPE_HELLO);
543
544 if (pim_msg_send(pim_ifp->pim_sock_fd,
545 qpim_all_pim_routers_addr,
546 pim_msg,
547 pim_msg_size,
548 ifp->name)) {
549 zlog_warn("%s: could not send PIM message on interface %s",
550 __PRETTY_FUNCTION__, ifp->name);
551 return -2;
552 }
553
554 return 0;
555}
556
557static int pim_hello_send(struct interface *ifp,
558 uint16_t holdtime)
559{
560 struct pim_interface *pim_ifp;
561
562 zassert(ifp);
563 pim_ifp = ifp->info;
564 zassert(pim_ifp);
565
566 if (hello_send(ifp, holdtime)) {
567 ++pim_ifp->pim_ifstat_hello_sendfail;
568
569 zlog_warn("Could not send PIM hello on interface %s",
570 ifp->name);
571 return -1;
572 }
573
574 ++pim_ifp->pim_ifstat_hello_sent;
575
576 return 0;
577}
578
579static void hello_resched(struct interface *ifp)
580{
581 struct pim_interface *pim_ifp;
582
583 zassert(ifp);
584 pim_ifp = ifp->info;
585 zassert(pim_ifp);
586
587 if (PIM_DEBUG_PIM_TRACE) {
588 zlog_debug("Rescheduling %d sec hello on interface %s",
589 pim_ifp->pim_hello_period, ifp->name);
590 }
591 THREAD_OFF(pim_ifp->t_pim_hello_timer);
592 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
593 on_pim_hello_send,
594 ifp, pim_ifp->pim_hello_period);
595}
596
597/*
598 Periodic hello timer
599 */
600static int on_pim_hello_send(struct thread *t)
601{
602 struct pim_interface *pim_ifp;
603 struct interface *ifp;
604
605 zassert(t);
606 ifp = THREAD_ARG(t);
607 zassert(ifp);
608
609 pim_ifp = ifp->info;
610
611 /*
612 * Schedule next hello
613 */
614 pim_ifp->t_pim_hello_timer = 0;
615 hello_resched(ifp);
616
617 /*
618 * Send hello
619 */
620 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
621}
622
623/*
624 RFC 4601: 4.3.1. Sending Hello Messages
625
626 Thus, if a router needs to send a Join/Prune or Assert message on an
627 interface on which it has not yet sent a Hello message with the
628 currently configured IP address, then it MUST immediately send the
629 relevant Hello message without waiting for the Hello Timer to
630 expire, followed by the Join/Prune or Assert message.
631 */
632void pim_hello_restart_now(struct interface *ifp)
633{
634 struct pim_interface *pim_ifp;
635
636 zassert(ifp);
637 pim_ifp = ifp->info;
638 zassert(pim_ifp);
639
640 /*
641 * Reset next hello timer
642 */
643 hello_resched(ifp);
644
645 /*
646 * Immediately send hello
647 */
648 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
649}
650
651/*
652 RFC 4601: 4.3.1. Sending Hello Messages
653
654 To allow new or rebooting routers to learn of PIM neighbors quickly,
655 when a Hello message is received from a new neighbor, or a Hello
656 message with a new GenID is received from an existing neighbor, a
657 new Hello message should be sent on this interface after a
658 randomized delay between 0 and Triggered_Hello_Delay.
659 */
660void pim_hello_restart_triggered(struct interface *ifp)
661{
662 struct pim_interface *pim_ifp;
663 int triggered_hello_delay_msec;
664 int random_msec;
665
666 zassert(ifp);
667 pim_ifp = ifp->info;
668 zassert(pim_ifp);
669
670 triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
671
672 if (pim_ifp->t_pim_hello_timer) {
673 long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
674 if (remain_msec <= triggered_hello_delay_msec) {
675 /* Rescheduling hello would increase the delay, then it's faster
676 to just wait for the scheduled periodic hello. */
677 return;
678 }
679
680 THREAD_OFF(pim_ifp->t_pim_hello_timer);
681 pim_ifp->t_pim_hello_timer = 0;
682 }
683 zassert(!pim_ifp->t_pim_hello_timer);
684
Donald Sharp77162682015-06-19 19:26:18 -0400685 random_msec = random() % (triggered_hello_delay_msec + 1);
Everton Marques871dbcf2009-08-11 15:43:05 -0300686
687 if (PIM_DEBUG_PIM_EVENTS) {
688 zlog_debug("Scheduling %d msec triggered hello on interface %s",
689 random_msec, ifp->name);
690 }
691
692 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
693 on_pim_hello_send,
Leonard Herve236b0152009-08-11 15:51:52 -0300694 ifp, random_msec);
Everton Marques871dbcf2009-08-11 15:43:05 -0300695}
696
697int pim_sock_add(struct interface *ifp)
698{
699 struct pim_interface *pim_ifp;
700 struct in_addr ifaddr;
Donald Sharpa031c4d2015-07-02 13:22:49 -0400701 uint32_t old_genid;
Everton Marques871dbcf2009-08-11 15:43:05 -0300702
703 pim_ifp = ifp->info;
704 zassert(pim_ifp);
705
706 if (pim_ifp->pim_sock_fd >= 0) {
707 zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
708 pim_ifp->pim_sock_fd, ifp->name);
709 return -1;
710 }
711
712 ifaddr = pim_ifp->primary_address;
713
714 pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
715 if (pim_ifp->pim_sock_fd < 0) {
716 zlog_warn("Could not open PIM socket on interface %s",
717 ifp->name);
718 return -2;
719 }
720
721 pim_ifp->t_pim_sock_read = 0;
722 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
723
Donald Sharpa031c4d2015-07-02 13:22:49 -0400724 /*
725 * Just ensure that the new generation id
726 * actually chooses something different.
727 * Actually ran across a case where this
728 * happened, pre-switch to random().
729 * While this is unlikely to happen now
730 * let's make sure it doesn't.
731 */
732 old_genid = pim_ifp->pim_generation_id;
733
734 while (old_genid == pim_ifp->pim_generation_id)
735 pim_ifp->pim_generation_id = random();
Everton Marques871dbcf2009-08-11 15:43:05 -0300736
Everton Marques85385f72015-01-19 18:25:45 -0200737 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
738 ifp->name, ifp->ifindex);
Everton Marques871dbcf2009-08-11 15:43:05 -0300739
740 /*
741 * Start receiving PIM messages
742 */
743 pim_sock_read_on(ifp);
744
745 /*
746 * Start sending PIM hello's
747 */
748 pim_hello_restart_triggered(ifp);
749
750 return 0;
751}