blob: 66fc59be58b869129d5234be6084585393fd08f0 [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;
272 int ifindex = -1;
273 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
379static int pim_sock_open(struct in_addr ifaddr, int ifindex)
380{
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
Balaji.Ged14fa02014-10-08 01:11:31 -0300524 if (PIM_DEBUG_PIM_PACKETS || 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)) {
564 zlog_warn("%s: could not send PIM message on interface %s",
565 __PRETTY_FUNCTION__, ifp->name);
566 return -2;
567 }
568
569 return 0;
570}
571
572static int pim_hello_send(struct interface *ifp,
573 uint16_t holdtime)
574{
575 struct pim_interface *pim_ifp;
576
577 zassert(ifp);
578 pim_ifp = ifp->info;
579 zassert(pim_ifp);
580
581 if (hello_send(ifp, holdtime)) {
582 ++pim_ifp->pim_ifstat_hello_sendfail;
583
584 zlog_warn("Could not send PIM hello on interface %s",
585 ifp->name);
586 return -1;
587 }
588
589 ++pim_ifp->pim_ifstat_hello_sent;
590
591 return 0;
592}
593
594static void hello_resched(struct interface *ifp)
595{
596 struct pim_interface *pim_ifp;
597
598 zassert(ifp);
599 pim_ifp = ifp->info;
600 zassert(pim_ifp);
601
602 if (PIM_DEBUG_PIM_TRACE) {
603 zlog_debug("Rescheduling %d sec hello on interface %s",
604 pim_ifp->pim_hello_period, ifp->name);
605 }
606 THREAD_OFF(pim_ifp->t_pim_hello_timer);
607 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
608 on_pim_hello_send,
609 ifp, pim_ifp->pim_hello_period);
610}
611
612/*
613 Periodic hello timer
614 */
615static int on_pim_hello_send(struct thread *t)
616{
617 struct pim_interface *pim_ifp;
618 struct interface *ifp;
619
620 zassert(t);
621 ifp = THREAD_ARG(t);
622 zassert(ifp);
623
624 pim_ifp = ifp->info;
625
626 /*
627 * Schedule next hello
628 */
629 pim_ifp->t_pim_hello_timer = 0;
630 hello_resched(ifp);
631
632 /*
633 * Send hello
634 */
635 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
636}
637
638/*
639 RFC 4601: 4.3.1. Sending Hello Messages
640
641 Thus, if a router needs to send a Join/Prune or Assert message on an
642 interface on which it has not yet sent a Hello message with the
643 currently configured IP address, then it MUST immediately send the
644 relevant Hello message without waiting for the Hello Timer to
645 expire, followed by the Join/Prune or Assert message.
646 */
647void pim_hello_restart_now(struct interface *ifp)
648{
649 struct pim_interface *pim_ifp;
650
651 zassert(ifp);
652 pim_ifp = ifp->info;
653 zassert(pim_ifp);
654
655 /*
656 * Reset next hello timer
657 */
658 hello_resched(ifp);
659
660 /*
661 * Immediately send hello
662 */
663 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
664}
665
666/*
667 RFC 4601: 4.3.1. Sending Hello Messages
668
669 To allow new or rebooting routers to learn of PIM neighbors quickly,
670 when a Hello message is received from a new neighbor, or a Hello
671 message with a new GenID is received from an existing neighbor, a
672 new Hello message should be sent on this interface after a
673 randomized delay between 0 and Triggered_Hello_Delay.
674 */
675void pim_hello_restart_triggered(struct interface *ifp)
676{
677 struct pim_interface *pim_ifp;
678 int triggered_hello_delay_msec;
679 int random_msec;
680
681 zassert(ifp);
682 pim_ifp = ifp->info;
683 zassert(pim_ifp);
684
685 triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
686
687 if (pim_ifp->t_pim_hello_timer) {
688 long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
689 if (remain_msec <= triggered_hello_delay_msec) {
690 /* Rescheduling hello would increase the delay, then it's faster
691 to just wait for the scheduled periodic hello. */
692 return;
693 }
694
695 THREAD_OFF(pim_ifp->t_pim_hello_timer);
696 pim_ifp->t_pim_hello_timer = 0;
697 }
698 zassert(!pim_ifp->t_pim_hello_timer);
699
Donald Sharp77162682015-06-19 19:26:18 -0400700 random_msec = random() % (triggered_hello_delay_msec + 1);
Everton Marques871dbcf2009-08-11 15:43:05 -0300701
702 if (PIM_DEBUG_PIM_EVENTS) {
703 zlog_debug("Scheduling %d msec triggered hello on interface %s",
704 random_msec, ifp->name);
705 }
706
707 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
708 on_pim_hello_send,
Leonard Herve236b0152009-08-11 15:51:52 -0300709 ifp, random_msec);
Everton Marques871dbcf2009-08-11 15:43:05 -0300710}
711
712int pim_sock_add(struct interface *ifp)
713{
714 struct pim_interface *pim_ifp;
715 struct in_addr ifaddr;
Donald Sharpa031c4d2015-07-02 13:22:49 -0400716 uint32_t old_genid;
Everton Marques871dbcf2009-08-11 15:43:05 -0300717
718 pim_ifp = ifp->info;
719 zassert(pim_ifp);
720
721 if (pim_ifp->pim_sock_fd >= 0) {
722 zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
723 pim_ifp->pim_sock_fd, ifp->name);
724 return -1;
725 }
726
727 ifaddr = pim_ifp->primary_address;
728
729 pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
730 if (pim_ifp->pim_sock_fd < 0) {
731 zlog_warn("Could not open PIM socket on interface %s",
732 ifp->name);
733 return -2;
734 }
735
736 pim_ifp->t_pim_sock_read = 0;
737 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
738
Donald Sharpa031c4d2015-07-02 13:22:49 -0400739 /*
740 * Just ensure that the new generation id
741 * actually chooses something different.
742 * Actually ran across a case where this
743 * happened, pre-switch to random().
744 * While this is unlikely to happen now
745 * let's make sure it doesn't.
746 */
747 old_genid = pim_ifp->pim_generation_id;
748
749 while (old_genid == pim_ifp->pim_generation_id)
750 pim_ifp->pim_generation_id = random();
Everton Marques871dbcf2009-08-11 15:43:05 -0300751
Everton Marques85385f72015-01-19 18:25:45 -0200752 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
753 ifp->name, ifp->ifindex);
Everton Marques871dbcf2009-08-11 15:43:05 -0300754
755 /*
756 * Start receiving PIM messages
757 */
758 pim_sock_read_on(ifp);
759
760 /*
761 * Start sending PIM hello's
762 */
763 pim_hello_restart_triggered(ifp);
764
765 return 0;
766}