blob: c52247578b67d42cfa70812e5b85be9ff40af08a [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
476#if 0
477 memset(&to, 0, sizeof(to));
478#endif
479 to.sin_family = AF_INET;
480 to.sin_addr = dst;
481#if 0
482 to.sin_port = htons(0);
483#endif
484 tolen = sizeof(to);
485
Everton Marques62738042009-11-18 10:44:13 -0200486 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
487 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
488 }
489
David Lampartera2c7f4b2015-03-03 21:03:52 +0100490 sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT,
491 (struct sockaddr *)&to, tolen);
Everton Marques871dbcf2009-08-11 15:43:05 -0300492 if (sent != (ssize_t) pim_msg_size) {
493 int e = errno;
494 char dst_str[100];
495 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
496 if (sent < 0) {
497 zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
498 __PRETTY_FUNCTION__,
499 dst_str, ifname, fd, pim_msg_size,
Everton Marquese96f0af2009-08-11 15:48:02 -0300500 e, safe_strerror(e));
Everton Marques871dbcf2009-08-11 15:43:05 -0300501 }
502 else {
David Lamparter5c697982012-02-16 04:47:56 +0100503 zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
Everton Marques871dbcf2009-08-11 15:43:05 -0300504 __PRETTY_FUNCTION__,
505 dst_str, ifname, fd,
506 pim_msg_size, sent);
507 }
508 return -1;
509 }
510
511 return 0;
512}
513
514static int hello_send(struct interface *ifp,
515 uint16_t holdtime)
516{
David Lamparterf8cfeb22012-02-16 04:31:08 +0000517 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
Everton Marques871dbcf2009-08-11 15:43:05 -0300518 struct pim_interface *pim_ifp;
519 int pim_tlv_size;
520 int pim_msg_size;
521
522 pim_ifp = ifp->info;
523
Donald Sharp6d853c42015-10-21 16:13:51 -0400524 if (PIM_DEBUG_PIM_HELLO) {
Everton Marques871dbcf2009-08-11 15:43:05 -0300525 char dst_str[100];
526 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str));
527 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",
528 __PRETTY_FUNCTION__,
529 dst_str, ifp->name,
530 holdtime,
531 pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec,
532 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
533 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
534 listcount(ifp->connected));
535 }
536
537 pim_tlv_size = pim_hello_build_tlv(ifp->name,
538 pim_msg + PIM_PIM_MIN_LEN,
539 sizeof(pim_msg) - PIM_PIM_MIN_LEN,
540 holdtime,
541 pim_ifp->pim_dr_priority,
542 pim_ifp->pim_generation_id,
543 pim_ifp->pim_propagation_delay_msec,
544 pim_ifp->pim_override_interval_msec,
545 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
546 ifp->connected);
547 if (pim_tlv_size < 0) {
548 return -1;
549 }
550
551 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
552
553 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
554 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
555
556 pim_msg_build_header(pim_msg, pim_msg_size,
557 PIM_MSG_TYPE_HELLO);
558
559 if (pim_msg_send(pim_ifp->pim_sock_fd,
560 qpim_all_pim_routers_addr,
561 pim_msg,
562 pim_msg_size,
563 ifp->name)) {
Donald Sharp6d853c42015-10-21 16:13:51 -0400564 if (PIM_DEBUG_PIM_HELLO) {
565 zlog_debug("%s: could not send PIM message on interface %s",
566 __PRETTY_FUNCTION__, ifp->name);
567 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300568 return -2;
569 }
570
571 return 0;
572}
573
574static int pim_hello_send(struct interface *ifp,
575 uint16_t holdtime)
576{
577 struct pim_interface *pim_ifp;
578
579 zassert(ifp);
580 pim_ifp = ifp->info;
581 zassert(pim_ifp);
582
583 if (hello_send(ifp, holdtime)) {
584 ++pim_ifp->pim_ifstat_hello_sendfail;
585
Donald Sharp6d853c42015-10-21 16:13:51 -0400586 if (PIM_DEBUG_PIM_HELLO) {
587 zlog_warn("Could not send PIM hello on interface %s",
588 ifp->name);
589 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300590 return -1;
591 }
592
593 ++pim_ifp->pim_ifstat_hello_sent;
594
595 return 0;
596}
597
598static void hello_resched(struct interface *ifp)
599{
600 struct pim_interface *pim_ifp;
601
602 zassert(ifp);
603 pim_ifp = ifp->info;
604 zassert(pim_ifp);
605
Donald Sharp6d853c42015-10-21 16:13:51 -0400606 if (PIM_DEBUG_PIM_HELLO) {
Everton Marques871dbcf2009-08-11 15:43:05 -0300607 zlog_debug("Rescheduling %d sec hello on interface %s",
608 pim_ifp->pim_hello_period, ifp->name);
609 }
610 THREAD_OFF(pim_ifp->t_pim_hello_timer);
611 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
612 on_pim_hello_send,
613 ifp, pim_ifp->pim_hello_period);
614}
615
616/*
617 Periodic hello timer
618 */
619static int on_pim_hello_send(struct thread *t)
620{
621 struct pim_interface *pim_ifp;
622 struct interface *ifp;
623
624 zassert(t);
625 ifp = THREAD_ARG(t);
626 zassert(ifp);
627
628 pim_ifp = ifp->info;
629
630 /*
631 * Schedule next hello
632 */
633 pim_ifp->t_pim_hello_timer = 0;
634 hello_resched(ifp);
635
636 /*
637 * Send hello
638 */
639 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
640}
641
642/*
643 RFC 4601: 4.3.1. Sending Hello Messages
644
645 Thus, if a router needs to send a Join/Prune or Assert message on an
646 interface on which it has not yet sent a Hello message with the
647 currently configured IP address, then it MUST immediately send the
648 relevant Hello message without waiting for the Hello Timer to
649 expire, followed by the Join/Prune or Assert message.
650 */
651void pim_hello_restart_now(struct interface *ifp)
652{
653 struct pim_interface *pim_ifp;
654
655 zassert(ifp);
656 pim_ifp = ifp->info;
657 zassert(pim_ifp);
658
659 /*
660 * Reset next hello timer
661 */
662 hello_resched(ifp);
663
664 /*
665 * Immediately send hello
666 */
667 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
668}
669
670/*
671 RFC 4601: 4.3.1. Sending Hello Messages
672
673 To allow new or rebooting routers to learn of PIM neighbors quickly,
674 when a Hello message is received from a new neighbor, or a Hello
675 message with a new GenID is received from an existing neighbor, a
676 new Hello message should be sent on this interface after a
677 randomized delay between 0 and Triggered_Hello_Delay.
678 */
679void pim_hello_restart_triggered(struct interface *ifp)
680{
681 struct pim_interface *pim_ifp;
682 int triggered_hello_delay_msec;
683 int random_msec;
684
685 zassert(ifp);
686 pim_ifp = ifp->info;
687 zassert(pim_ifp);
688
689 triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
690
691 if (pim_ifp->t_pim_hello_timer) {
692 long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
693 if (remain_msec <= triggered_hello_delay_msec) {
694 /* Rescheduling hello would increase the delay, then it's faster
695 to just wait for the scheduled periodic hello. */
696 return;
697 }
698
699 THREAD_OFF(pim_ifp->t_pim_hello_timer);
700 pim_ifp->t_pim_hello_timer = 0;
701 }
702 zassert(!pim_ifp->t_pim_hello_timer);
703
Donald Sharp77162682015-06-19 19:26:18 -0400704 random_msec = random() % (triggered_hello_delay_msec + 1);
Everton Marques871dbcf2009-08-11 15:43:05 -0300705
Donald Sharp6d853c42015-10-21 16:13:51 -0400706 if (PIM_DEBUG_PIM_HELLO) {
Everton Marques871dbcf2009-08-11 15:43:05 -0300707 zlog_debug("Scheduling %d msec triggered hello on interface %s",
708 random_msec, ifp->name);
709 }
710
711 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
712 on_pim_hello_send,
Leonard Herve236b0152009-08-11 15:51:52 -0300713 ifp, random_msec);
Everton Marques871dbcf2009-08-11 15:43:05 -0300714}
715
716int pim_sock_add(struct interface *ifp)
717{
718 struct pim_interface *pim_ifp;
719 struct in_addr ifaddr;
Donald Sharpa031c4d2015-07-02 13:22:49 -0400720 uint32_t old_genid;
Everton Marques871dbcf2009-08-11 15:43:05 -0300721
722 pim_ifp = ifp->info;
723 zassert(pim_ifp);
724
725 if (pim_ifp->pim_sock_fd >= 0) {
726 zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
727 pim_ifp->pim_sock_fd, ifp->name);
728 return -1;
729 }
730
731 ifaddr = pim_ifp->primary_address;
732
733 pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
734 if (pim_ifp->pim_sock_fd < 0) {
735 zlog_warn("Could not open PIM socket on interface %s",
736 ifp->name);
737 return -2;
738 }
739
740 pim_ifp->t_pim_sock_read = 0;
741 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
742
Donald Sharpa031c4d2015-07-02 13:22:49 -0400743 /*
744 * Just ensure that the new generation id
745 * actually chooses something different.
746 * Actually ran across a case where this
747 * happened, pre-switch to random().
748 * While this is unlikely to happen now
749 * let's make sure it doesn't.
750 */
751 old_genid = pim_ifp->pim_generation_id;
752
753 while (old_genid == pim_ifp->pim_generation_id)
754 pim_ifp->pim_generation_id = random();
Everton Marques871dbcf2009-08-11 15:43:05 -0300755
Everton Marques85385f72015-01-19 18:25:45 -0200756 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
757 ifp->name, ifp->ifindex);
Everton Marques871dbcf2009-08-11 15:43:05 -0300758
759 /*
760 * Start receiving PIM messages
761 */
762 pim_sock_read_on(ifp);
763
764 /*
765 * Start sending PIM hello's
766 */
767 pim_hello_restart_triggered(ifp);
768
769 return 0;
770}