blob: c52b0d39333813585ad00a41456b3c5852aaf9bd [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
Donald Sharp4edf1c62015-10-01 12:40:52 -0400209 if (pim_type == PIM_MSG_TYPE_REGISTER ||
210 pim_type == PIM_MSG_TYPE_REG_STOP ||
211 pim_type == PIM_MSG_TYPE_BOOTSTRAP ||
212 pim_type == PIM_MSG_TYPE_GRAFT ||
213 pim_type == PIM_MSG_TYPE_GRAFT_ACK ||
214 pim_type == PIM_MSG_TYPE_CANDIDATE)
215 {
216 if (PIM_DEBUG_PIM_PACKETS) {
217 zlog_debug("Recv PIM packet type %d which is not currently understood",
218 pim_type);
219 }
220 return -1;
221 }
222
Everton Marques871dbcf2009-08-11 15:43:05 -0300223 if (pim_type == PIM_MSG_TYPE_HELLO) {
Everton Marques777fe1f2014-02-14 14:16:07 -0200224 int result = pim_hello_recv(ifp,
225 ip_hdr->ip_src,
226 pim_msg + PIM_MSG_HEADER_LEN,
227 pim_msg_len - PIM_MSG_HEADER_LEN);
Everton Marques777fe1f2014-02-14 14:16:07 -0200228 return result;
Everton Marques871dbcf2009-08-11 15:43:05 -0300229 }
230
231 neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
232 if (!neigh) {
233 zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
234 __FILE__, __PRETTY_FUNCTION__,
235 pim_type, src_str, ifp->name);
236 return -1;
237 }
238
239 switch (pim_type) {
240 case PIM_MSG_TYPE_JOIN_PRUNE:
241 return pim_joinprune_recv(ifp, neigh,
242 ip_hdr->ip_src,
243 pim_msg + PIM_MSG_HEADER_LEN,
244 pim_msg_len - PIM_MSG_HEADER_LEN);
245 case PIM_MSG_TYPE_ASSERT:
246 return pim_assert_recv(ifp, neigh,
247 ip_hdr->ip_src,
248 pim_msg + PIM_MSG_HEADER_LEN,
249 pim_msg_len - PIM_MSG_HEADER_LEN);
250 default:
251 zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s",
252 __FILE__, __PRETTY_FUNCTION__,
253 pim_type, src_str, ifp->name);
254 }
255
256 return -1;
257}
258
259static void pim_sock_read_on(struct interface *ifp);
260
261static int pim_sock_read(struct thread *t)
262{
263 struct interface *ifp;
264 struct pim_interface *pim_ifp;
265 int fd;
266 struct sockaddr_in from;
267 struct sockaddr_in to;
268 socklen_t fromlen = sizeof(from);
269 socklen_t tolen = sizeof(to);
David Lamparterf8cfeb22012-02-16 04:31:08 +0000270 uint8_t buf[PIM_PIM_BUFSIZE_READ];
Everton Marques871dbcf2009-08-11 15:43:05 -0300271 int len;
Paul Jakma9099f9b2016-01-18 10:12:10 +0000272 ifindex_t ifindex = -1;
Everton Marques871dbcf2009-08-11 15:43:05 -0300273 int result = -1; /* defaults to bad */
274
275 zassert(t);
276
277 ifp = THREAD_ARG(t);
278 zassert(ifp);
279
280 fd = THREAD_FD(t);
281
282 pim_ifp = ifp->info;
283 zassert(pim_ifp);
284
285 zassert(fd == pim_ifp->pim_sock_fd);
286
287 len = pim_socket_recvfromto(fd, buf, sizeof(buf),
288 &from, &fromlen,
289 &to, &tolen,
290 &ifindex);
291 if (len < 0) {
292 zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s",
Everton Marquese96f0af2009-08-11 15:48:02 -0300293 fd, errno, safe_strerror(errno));
Everton Marques871dbcf2009-08-11 15:43:05 -0300294 goto done;
295 }
296
297 if (PIM_DEBUG_PIM_PACKETS) {
298 char from_str[100];
299 char to_str[100];
300
301 if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str)))
302 sprintf(from_str, "<from?>");
303 if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str)))
304 sprintf(to_str, "<to?>");
305
306 zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)",
307 len, from_str, to_str, fd, ifindex, ifp->ifindex);
308 }
309
Everton Marques62738042009-11-18 10:44:13 -0200310 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
311 pim_pkt_dump(__PRETTY_FUNCTION__, buf, len);
312 }
313
Everton Marques871dbcf2009-08-11 15:43:05 -0300314#ifdef PIM_CHECK_RECV_IFINDEX_SANITY
315 /* ifindex sanity check */
316 if (ifindex != (int) ifp->ifindex) {
317 char from_str[100];
318 char to_str[100];
319 struct interface *recv_ifp;
320
321 if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
322 sprintf(from_str, "<from?>");
323 if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
324 sprintf(to_str, "<to?>");
325
326 recv_ifp = if_lookup_by_index(ifindex);
327 if (recv_ifp) {
328 zassert(ifindex == (int) recv_ifp->ifindex);
329 }
330
331#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
332 zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
333 from_str, to_str, fd,
334 ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
335 ifp->ifindex, ifp->name);
336#endif
337 goto done;
338 }
339#endif
340
Everton Marques777fe1f2014-02-14 14:16:07 -0200341 int fail = pim_pim_packet(ifp, buf, len);
342 if (fail) {
343 zlog_warn("%s: pim_pim_packet() return=%d",
344 __PRETTY_FUNCTION__, fail);
Everton Marques871dbcf2009-08-11 15:43:05 -0300345 goto done;
346 }
347
348 result = 0; /* good */
349
350 done:
351 pim_sock_read_on(ifp);
352
353 if (result) {
354 ++pim_ifp->pim_ifstat_hello_recvfail;
355 }
356
357 return result;
358}
359
360static void pim_sock_read_on(struct interface *ifp)
361{
362 struct pim_interface *pim_ifp;
363
364 zassert(ifp);
365 zassert(ifp->info);
366
367 pim_ifp = ifp->info;
368
369 if (PIM_DEBUG_PIM_TRACE) {
370 zlog_debug("Scheduling READ event on PIM socket fd=%d",
371 pim_ifp->pim_sock_fd);
372 }
373 pim_ifp->t_pim_sock_read = 0;
374 zassert(!pim_ifp->t_pim_sock_read);
375 THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
376 pim_ifp->pim_sock_fd);
377}
378
Paul Jakma9099f9b2016-01-18 10:12:10 +0000379static int pim_sock_open(struct in_addr ifaddr, ifindex_t ifindex)
Everton Marques871dbcf2009-08-11 15:43:05 -0300380{
381 int fd;
382
383 fd = pim_socket_mcast(IPPROTO_PIM, ifaddr, 0 /* loop=false */);
384 if (fd < 0)
385 return -1;
386
387 if (pim_socket_join(fd, qpim_all_pim_routers_addr, ifaddr, ifindex)) {
Donald Sharp44d03fd2015-09-08 15:02:07 -0400388 close(fd);
Everton Marques871dbcf2009-08-11 15:43:05 -0300389 return -2;
390 }
391
392 return fd;
393}
394
395void pim_ifstat_reset(struct interface *ifp)
396{
397 struct pim_interface *pim_ifp;
398
399 zassert(ifp);
400
401 pim_ifp = ifp->info;
402 if (!pim_ifp) {
403 return;
404 }
405
406 pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
407 pim_ifp->pim_ifstat_hello_sent = 0;
408 pim_ifp->pim_ifstat_hello_sendfail = 0;
409 pim_ifp->pim_ifstat_hello_recv = 0;
410 pim_ifp->pim_ifstat_hello_recvfail = 0;
411}
412
413void pim_sock_reset(struct interface *ifp)
414{
415 struct pim_interface *pim_ifp;
416
417 zassert(ifp);
418 zassert(ifp->info);
419
420 pim_ifp = ifp->info;
421
422 pim_ifp->primary_address = pim_find_primary_addr(ifp);
423
424 pim_ifp->pim_sock_fd = -1;
425 pim_ifp->pim_sock_creation = 0;
426 pim_ifp->t_pim_sock_read = 0;
427
428 pim_ifp->t_pim_hello_timer = 0;
429 pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
430 pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
431 pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
432 pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
433 pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
434 pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
435 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
436 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
437 }
438 else {
439 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
440 }
441
442 /* neighbors without lan_delay */
443 pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
444 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
445 pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
446
447 /* DR Election */
448 pim_ifp->pim_dr_election_last = 0; /* timestamp */
449 pim_ifp->pim_dr_election_count = 0;
Everton Marques777fe1f2014-02-14 14:16:07 -0200450 pim_ifp->pim_dr_election_changes = 0;
Everton Marques871dbcf2009-08-11 15:43:05 -0300451 pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */
452 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
453
454 pim_ifstat_reset(ifp);
455}
456
457int pim_msg_send(int fd,
458 struct in_addr dst,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000459 uint8_t *pim_msg,
Everton Marques871dbcf2009-08-11 15:43:05 -0300460 int pim_msg_size,
461 const char *ifname)
462{
463 ssize_t sent;
464 struct sockaddr_in to;
465 socklen_t tolen;
466
467 if (PIM_DEBUG_PIM_PACKETS) {
468 char dst_str[100];
469 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
470 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
471 __PRETTY_FUNCTION__,
472 dst_str, ifname, pim_msg_size,
473 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg));
474 }
475
Everton Marques871dbcf2009-08-11 15:43:05 -0300476 memset(&to, 0, sizeof(to));
Everton Marques871dbcf2009-08-11 15:43:05 -0300477 to.sin_family = AF_INET;
478 to.sin_addr = dst;
Everton Marques871dbcf2009-08-11 15:43:05 -0300479 tolen = sizeof(to);
480
Everton Marques62738042009-11-18 10:44:13 -0200481 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
482 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
483 }
484
David Lampartera2c7f4b2015-03-03 21:03:52 +0100485 sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT,
486 (struct sockaddr *)&to, tolen);
Everton Marques871dbcf2009-08-11 15:43:05 -0300487 if (sent != (ssize_t) pim_msg_size) {
488 int e = errno;
489 char dst_str[100];
490 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
491 if (sent < 0) {
492 zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
493 __PRETTY_FUNCTION__,
494 dst_str, ifname, fd, pim_msg_size,
Everton Marquese96f0af2009-08-11 15:48:02 -0300495 e, safe_strerror(e));
Everton Marques871dbcf2009-08-11 15:43:05 -0300496 }
497 else {
David Lamparter5c697982012-02-16 04:47:56 +0100498 zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
Everton Marques871dbcf2009-08-11 15:43:05 -0300499 __PRETTY_FUNCTION__,
500 dst_str, ifname, fd,
501 pim_msg_size, sent);
502 }
503 return -1;
504 }
505
506 return 0;
507}
508
509static int hello_send(struct interface *ifp,
510 uint16_t holdtime)
511{
David Lamparterf8cfeb22012-02-16 04:31:08 +0000512 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
Everton Marques871dbcf2009-08-11 15:43:05 -0300513 struct pim_interface *pim_ifp;
514 int pim_tlv_size;
515 int pim_msg_size;
516
517 pim_ifp = ifp->info;
518
Donald Sharp6d853c42015-10-21 16:13:51 -0400519 if (PIM_DEBUG_PIM_HELLO) {
Everton Marques871dbcf2009-08-11 15:43:05 -0300520 char dst_str[100];
521 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str));
522 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",
523 __PRETTY_FUNCTION__,
524 dst_str, ifp->name,
525 holdtime,
526 pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec,
527 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
528 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
529 listcount(ifp->connected));
530 }
531
532 pim_tlv_size = pim_hello_build_tlv(ifp->name,
533 pim_msg + PIM_PIM_MIN_LEN,
534 sizeof(pim_msg) - PIM_PIM_MIN_LEN,
535 holdtime,
536 pim_ifp->pim_dr_priority,
537 pim_ifp->pim_generation_id,
538 pim_ifp->pim_propagation_delay_msec,
539 pim_ifp->pim_override_interval_msec,
540 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
541 ifp->connected);
542 if (pim_tlv_size < 0) {
543 return -1;
544 }
545
546 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
547
548 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
549 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
550
551 pim_msg_build_header(pim_msg, pim_msg_size,
552 PIM_MSG_TYPE_HELLO);
553
554 if (pim_msg_send(pim_ifp->pim_sock_fd,
555 qpim_all_pim_routers_addr,
556 pim_msg,
557 pim_msg_size,
558 ifp->name)) {
Donald Sharp6d853c42015-10-21 16:13:51 -0400559 if (PIM_DEBUG_PIM_HELLO) {
560 zlog_debug("%s: could not send PIM message on interface %s",
561 __PRETTY_FUNCTION__, ifp->name);
562 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300563 return -2;
564 }
565
566 return 0;
567}
568
569static int pim_hello_send(struct interface *ifp,
570 uint16_t holdtime)
571{
572 struct pim_interface *pim_ifp;
573
574 zassert(ifp);
575 pim_ifp = ifp->info;
576 zassert(pim_ifp);
577
578 if (hello_send(ifp, holdtime)) {
579 ++pim_ifp->pim_ifstat_hello_sendfail;
580
Donald Sharp6d853c42015-10-21 16:13:51 -0400581 if (PIM_DEBUG_PIM_HELLO) {
582 zlog_warn("Could not send PIM hello on interface %s",
583 ifp->name);
584 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300585 return -1;
586 }
587
588 ++pim_ifp->pim_ifstat_hello_sent;
589
590 return 0;
591}
592
593static void hello_resched(struct interface *ifp)
594{
595 struct pim_interface *pim_ifp;
596
597 zassert(ifp);
598 pim_ifp = ifp->info;
599 zassert(pim_ifp);
600
Donald Sharp6d853c42015-10-21 16:13:51 -0400601 if (PIM_DEBUG_PIM_HELLO) {
Everton Marques871dbcf2009-08-11 15:43:05 -0300602 zlog_debug("Rescheduling %d sec hello on interface %s",
603 pim_ifp->pim_hello_period, ifp->name);
604 }
605 THREAD_OFF(pim_ifp->t_pim_hello_timer);
606 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
607 on_pim_hello_send,
608 ifp, pim_ifp->pim_hello_period);
609}
610
611/*
612 Periodic hello timer
613 */
614static int on_pim_hello_send(struct thread *t)
615{
616 struct pim_interface *pim_ifp;
617 struct interface *ifp;
618
619 zassert(t);
620 ifp = THREAD_ARG(t);
621 zassert(ifp);
622
623 pim_ifp = ifp->info;
624
625 /*
626 * Schedule next hello
627 */
628 pim_ifp->t_pim_hello_timer = 0;
629 hello_resched(ifp);
630
631 /*
632 * Send hello
633 */
634 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
635}
636
637/*
638 RFC 4601: 4.3.1. Sending Hello Messages
639
640 Thus, if a router needs to send a Join/Prune or Assert message on an
641 interface on which it has not yet sent a Hello message with the
642 currently configured IP address, then it MUST immediately send the
643 relevant Hello message without waiting for the Hello Timer to
644 expire, followed by the Join/Prune or Assert message.
645 */
646void pim_hello_restart_now(struct interface *ifp)
647{
648 struct pim_interface *pim_ifp;
649
650 zassert(ifp);
651 pim_ifp = ifp->info;
652 zassert(pim_ifp);
653
654 /*
655 * Reset next hello timer
656 */
657 hello_resched(ifp);
658
659 /*
660 * Immediately send hello
661 */
662 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
663}
664
665/*
666 RFC 4601: 4.3.1. Sending Hello Messages
667
668 To allow new or rebooting routers to learn of PIM neighbors quickly,
669 when a Hello message is received from a new neighbor, or a Hello
670 message with a new GenID is received from an existing neighbor, a
671 new Hello message should be sent on this interface after a
672 randomized delay between 0 and Triggered_Hello_Delay.
673 */
674void pim_hello_restart_triggered(struct interface *ifp)
675{
676 struct pim_interface *pim_ifp;
677 int triggered_hello_delay_msec;
678 int random_msec;
679
680 zassert(ifp);
681 pim_ifp = ifp->info;
682 zassert(pim_ifp);
683
684 triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
685
686 if (pim_ifp->t_pim_hello_timer) {
687 long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
688 if (remain_msec <= triggered_hello_delay_msec) {
689 /* Rescheduling hello would increase the delay, then it's faster
690 to just wait for the scheduled periodic hello. */
691 return;
692 }
693
694 THREAD_OFF(pim_ifp->t_pim_hello_timer);
695 pim_ifp->t_pim_hello_timer = 0;
696 }
697 zassert(!pim_ifp->t_pim_hello_timer);
698
Donald Sharp77162682015-06-19 19:26:18 -0400699 random_msec = random() % (triggered_hello_delay_msec + 1);
Everton Marques871dbcf2009-08-11 15:43:05 -0300700
Donald Sharp6d853c42015-10-21 16:13:51 -0400701 if (PIM_DEBUG_PIM_HELLO) {
Everton Marques871dbcf2009-08-11 15:43:05 -0300702 zlog_debug("Scheduling %d msec triggered hello on interface %s",
703 random_msec, ifp->name);
704 }
705
706 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
707 on_pim_hello_send,
Leonard Herve236b0152009-08-11 15:51:52 -0300708 ifp, random_msec);
Everton Marques871dbcf2009-08-11 15:43:05 -0300709}
710
711int pim_sock_add(struct interface *ifp)
712{
713 struct pim_interface *pim_ifp;
714 struct in_addr ifaddr;
Donald Sharpa031c4d2015-07-02 13:22:49 -0400715 uint32_t old_genid;
Everton Marques871dbcf2009-08-11 15:43:05 -0300716
717 pim_ifp = ifp->info;
718 zassert(pim_ifp);
719
720 if (pim_ifp->pim_sock_fd >= 0) {
721 zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
722 pim_ifp->pim_sock_fd, ifp->name);
723 return -1;
724 }
725
726 ifaddr = pim_ifp->primary_address;
727
728 pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
729 if (pim_ifp->pim_sock_fd < 0) {
730 zlog_warn("Could not open PIM socket on interface %s",
731 ifp->name);
732 return -2;
733 }
734
735 pim_ifp->t_pim_sock_read = 0;
736 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
737
Donald Sharpa031c4d2015-07-02 13:22:49 -0400738 /*
739 * Just ensure that the new generation id
740 * actually chooses something different.
741 * Actually ran across a case where this
742 * happened, pre-switch to random().
743 * While this is unlikely to happen now
744 * let's make sure it doesn't.
745 */
746 old_genid = pim_ifp->pim_generation_id;
747
748 while (old_genid == pim_ifp->pim_generation_id)
749 pim_ifp->pim_generation_id = random();
Everton Marques871dbcf2009-08-11 15:43:05 -0300750
Everton Marques85385f72015-01-19 18:25:45 -0200751 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
752 ifp->name, ifp->ifindex);
Everton Marques871dbcf2009-08-11 15:43:05 -0300753
754 /*
755 * Start receiving PIM messages
756 */
757 pim_sock_read_on(ifp);
758
759 /*
760 * Start sending PIM hello's
761 */
762 pim_hello_restart_triggered(ifp);
763
764 return 0;
765}