]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_pim.c
pim-anycast-rp: Add limited support for secondary addresses.
[mirror_frr.git] / pimd / pim_pim.c
CommitLineData
12e41d03
DL
1/*
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
12e41d03
DL
20*/
21
22#include <zebra.h>
23
24#include "log.h"
25#include "thread.h"
26#include "memory.h"
744d91b3 27#include "if.h"
12e41d03
DL
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"
77e390e5 42#include "pim_register.h"
12e41d03
DL
43
44static int on_pim_hello_send(struct thread *t);
45static int pim_hello_send(struct interface *ifp,
46 uint16_t holdtime);
47
7643f0a1
DS
48static
49const char *pim_pim_msgtype2str (enum pim_msg_type type)
50{
51 switch (type)
52 {
53 case PIM_MSG_TYPE_HELLO: return "HELLO";
54 case PIM_MSG_TYPE_REGISTER: return "REGISTER";
55 case PIM_MSG_TYPE_REG_STOP: return "REGSTOP";
7f0c1c5f 56 case PIM_MSG_TYPE_JOIN_PRUNE: return "JOINPRUNE";
7643f0a1
DS
57 case PIM_MSG_TYPE_BOOTSTRAP: return "BOOT";
58 case PIM_MSG_TYPE_ASSERT: return "ASSERT";
59 case PIM_MSG_TYPE_GRAFT: return "GRAFT";
60 case PIM_MSG_TYPE_GRAFT_ACK: return "GACK";
61 case PIM_MSG_TYPE_CANDIDATE: return "CANDIDATE";
62 }
63
64 return "UNKNOWN";
65}
66
12e41d03
DL
67static void sock_close(struct interface *ifp)
68{
69 struct pim_interface *pim_ifp = ifp->info;
70
71 if (PIM_DEBUG_PIM_TRACE) {
72 if (pim_ifp->t_pim_sock_read) {
73 zlog_debug("Cancelling READ event for PIM socket fd=%d on interface %s",
74 pim_ifp->pim_sock_fd,
75 ifp->name);
76 }
77 }
78 THREAD_OFF(pim_ifp->t_pim_sock_read);
79
80 if (PIM_DEBUG_PIM_TRACE) {
81 if (pim_ifp->t_pim_hello_timer) {
82 zlog_debug("Cancelling PIM hello timer for interface %s",
83 ifp->name);
84 }
85 }
86 THREAD_OFF(pim_ifp->t_pim_hello_timer);
87
88 if (PIM_DEBUG_PIM_TRACE) {
89 zlog_debug("Deleting PIM socket fd=%d on interface %s",
90 pim_ifp->pim_sock_fd, ifp->name);
91 }
92
6abb1fc2
DS
93 /*
94 * If the fd is already deleted no need to do anything here
95 */
96 if (pim_ifp->pim_sock_fd > 0 && close(pim_ifp->pim_sock_fd)) {
12e41d03
DL
97 zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
98 pim_ifp->pim_sock_fd, ifp->name,
99 errno, safe_strerror(errno));
100 }
101
102 pim_ifp->pim_sock_fd = -1;
103 pim_ifp->pim_sock_creation = 0;
12e41d03
DL
104}
105
106void pim_sock_delete(struct interface *ifp, const char *delete_message)
107{
108 zlog_info("PIM INTERFACE DOWN: on interface %s: %s",
109 ifp->name, delete_message);
110
111 if (!ifp->info) {
112 zlog_err("%s: %s: but PIM not enabled on interface %s (!)",
113 __PRETTY_FUNCTION__, delete_message, ifp->name);
114 return;
115 }
116
117 /*
118 RFC 4601: 4.3.1. Sending Hello Messages
119
120 Before an interface goes down or changes primary IP address, a Hello
121 message with a zero HoldTime should be sent immediately (with the
122 old IP address if the IP address changed).
123 */
124 pim_hello_send(ifp, 0 /* zero-sec holdtime */);
125
126 pim_neighbor_delete_all(ifp, delete_message);
127
128 sock_close(ifp);
129}
130
131int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
132{
133 struct ip *ip_hdr;
134 size_t ip_hlen; /* ip header length in bytes */
eaa54bdb
DW
135 char src_str[INET_ADDRSTRLEN];
136 char dst_str[INET_ADDRSTRLEN];
12e41d03
DL
137 uint8_t *pim_msg;
138 int pim_msg_len;
139 uint8_t pim_version;
7643f0a1 140 enum pim_msg_type pim_type;
12e41d03
DL
141 uint16_t pim_checksum; /* received checksum */
142 uint16_t checksum; /* computed checksum */
143 struct pim_neighbor *neigh;
144
12e41d03 145 if (len < sizeof(*ip_hdr)) {
def1e807
DS
146 if (PIM_DEBUG_PIM_PACKETS)
147 zlog_debug("PIM packet size=%zu shorter than minimum=%zu",
148 len, sizeof(*ip_hdr));
12e41d03
DL
149 return -1;
150 }
151
152 ip_hdr = (struct ip *) buf;
12e41d03
DL
153 ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
154
12e41d03 155 if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) {
def1e807
DS
156 if (PIM_DEBUG_PIM_PACKETS)
157 zlog_debug("IP packet protocol=%d is not PIM=%d",
158 ip_hdr->ip_p, PIM_IP_PROTO_PIM);
12e41d03
DL
159 return -1;
160 }
161
162 if (ip_hlen < PIM_IP_HEADER_MIN_LEN) {
def1e807
DS
163 if (PIM_DEBUG_PIM_PACKETS)
164 zlog_debug("IP packet header size=%zu shorter than minimum=%d",
0f055c0d 165 ip_hlen, PIM_IP_HEADER_MIN_LEN);
12e41d03
DL
166 return -1;
167 }
168 if (ip_hlen > PIM_IP_HEADER_MAX_LEN) {
def1e807
DS
169 if (PIM_DEBUG_PIM_PACKETS)
170 zlog_debug("IP packet header size=%zu greater than maximum=%d",
0f055c0d 171 ip_hlen, PIM_IP_HEADER_MAX_LEN);
12e41d03
DL
172 return -1;
173 }
174
175 pim_msg = buf + ip_hlen;
176 pim_msg_len = len - ip_hlen;
177
12e41d03 178 if (pim_msg_len < PIM_PIM_MIN_LEN) {
0f055c0d
DS
179 if (PIM_DEBUG_PIM_PACKETS)
180 zlog_debug("PIM message size=%d shorter than minimum=%d",
181 pim_msg_len, PIM_PIM_MIN_LEN);
12e41d03
DL
182 return -1;
183 }
184
185 pim_version = PIM_MSG_HDR_GET_VERSION(pim_msg);
186 pim_type = PIM_MSG_HDR_GET_TYPE(pim_msg);
187
188 if (pim_version != PIM_PROTO_VERSION) {
def1e807
DS
189 if (PIM_DEBUG_PIM_PACKETS)
190 zlog_debug("Ignoring PIM pkt from %s with unsupported version: %d",
191 ifp->name, pim_version);
12e41d03
DL
192 return -1;
193 }
194
195 /* save received checksum */
196 pim_checksum = PIM_MSG_HDR_GET_CHECKSUM(pim_msg);
197
198 /* for computing checksum */
199 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0;
200
201 checksum = in_cksum(pim_msg, pim_msg_len);
202 if (checksum != pim_checksum) {
def1e807
DS
203 if (PIM_DEBUG_PIM_PACKETS)
204 zlog_debug("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
205 ifp->name, pim_checksum, checksum);
12e41d03
DL
206 return -1;
207 }
208
209 if (PIM_DEBUG_PIM_PACKETS) {
0f055c0d
DS
210 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
211 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str, sizeof(dst_str));
7643f0a1
DS
212 zlog_debug("Recv PIM %s packet from %s to %s on %s: ttl=%d pim_version=%d pim_msg_size=%d checksum=%x",
213 pim_pim_msgtype2str (pim_type), src_str, dst_str, ifp->name,
214 ip_hdr->ip_ttl, pim_version, pim_msg_len, checksum);
0f055c0d
DS
215 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
216 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
217 }
12e41d03
DL
218 }
219
4dffc880 220 switch (pim_type)
566b83cf 221 {
4dffc880
DS
222 case PIM_MSG_TYPE_HELLO:
223 return pim_hello_recv (ifp,
224 ip_hdr->ip_src,
225 pim_msg + PIM_MSG_HEADER_LEN,
226 pim_msg_len - PIM_MSG_HEADER_LEN);
227 break;
228 case PIM_MSG_TYPE_REGISTER:
229 return pim_register_recv (ifp,
230 ip_hdr->ip_dst,
231 ip_hdr->ip_src,
232 pim_msg + PIM_MSG_HEADER_LEN,
233 pim_msg_len - PIM_MSG_HEADER_LEN);
234 break;
235 case PIM_MSG_TYPE_REG_STOP:
56638739
DS
236 return pim_register_stop_recv (pim_msg + PIM_MSG_HEADER_LEN,
237 pim_msg_len - PIM_MSG_HEADER_LEN);
4dffc880
DS
238 break;
239 case PIM_MSG_TYPE_JOIN_PRUNE:
240 neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
241 if (!neigh) {
def1e807
DS
242 if (PIM_DEBUG_PIM_PACKETS)
243 zlog_debug("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
244 __FILE__, __PRETTY_FUNCTION__,
245 pim_type, src_str, ifp->name);
4dffc880
DS
246 return -1;
247 }
248 return pim_joinprune_recv(ifp, neigh,
249 ip_hdr->ip_src,
250 pim_msg + PIM_MSG_HEADER_LEN,
251 pim_msg_len - PIM_MSG_HEADER_LEN);
252 break;
253 case PIM_MSG_TYPE_ASSERT:
254 neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
255 if (!neigh) {
def1e807
DS
256 if (PIM_DEBUG_PIM_PACKETS)
257 zlog_debug("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
258 __FILE__, __PRETTY_FUNCTION__,
259 pim_type, src_str, ifp->name);
4dffc880
DS
260 return -1;
261 }
262 return pim_assert_recv(ifp, neigh,
263 ip_hdr->ip_src,
264 pim_msg + PIM_MSG_HEADER_LEN,
265 pim_msg_len - PIM_MSG_HEADER_LEN);
266 break;
267 default:
566b83cf
DS
268 if (PIM_DEBUG_PIM_PACKETS) {
269 zlog_debug("Recv PIM packet type %d which is not currently understood",
270 pim_type);
271 }
272 return -1;
273 }
12e41d03
DL
274 return -1;
275}
276
277static void pim_sock_read_on(struct interface *ifp);
278
279static int pim_sock_read(struct thread *t)
280{
281 struct interface *ifp;
282 struct pim_interface *pim_ifp;
283 int fd;
284 struct sockaddr_in from;
285 struct sockaddr_in to;
286 socklen_t fromlen = sizeof(from);
287 socklen_t tolen = sizeof(to);
288 uint8_t buf[PIM_PIM_BUFSIZE_READ];
289 int len;
b892f1dd 290 ifindex_t ifindex = -1;
12e41d03 291 int result = -1; /* defaults to bad */
db48bcb2
DS
292 static long long count = 0;
293 int cont = 1;
12e41d03 294
12e41d03 295 ifp = THREAD_ARG(t);
12e41d03
DL
296 fd = THREAD_FD(t);
297
298 pim_ifp = ifp->info;
12e41d03 299
db48bcb2
DS
300 while (cont)
301 {
302 len = pim_socket_recvfromto(fd, buf, sizeof(buf),
303 &from, &fromlen,
304 &to, &tolen,
305 &ifindex);
306 if (len < 0)
307 {
308 if (errno == EINTR)
309 continue;
310 if (errno == EWOULDBLOCK || errno == EAGAIN)
311 {
312 cont = 0;
313 break;
314 }
315 if (PIM_DEBUG_PIM_PACKETS)
316 zlog_debug ("Received errno: %d %s", errno, safe_strerror (errno));
317 goto done;
318 }
12e41d03 319
12e41d03 320#ifdef PIM_CHECK_RECV_IFINDEX_SANITY
db48bcb2
DS
321 /* ifindex sanity check */
322 if (ifindex != (int) ifp->ifindex) {
323 char from_str[INET_ADDRSTRLEN];
324 char to_str[INET_ADDRSTRLEN];
325 struct interface *recv_ifp;
326
327 if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
328 sprintf(from_str, "<from?>");
329 if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
330 sprintf(to_str, "<to?>");
331
332 recv_ifp = if_lookup_by_index(ifindex);
333 if (recv_ifp) {
334 zassert(ifindex == (int) recv_ifp->ifindex);
335 }
12e41d03
DL
336
337#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
db48bcb2
DS
338 zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
339 from_str, to_str, fd,
340 ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
341 ifp->ifindex, ifp->name);
12e41d03 342#endif
db48bcb2
DS
343 goto done;
344 }
12e41d03
DL
345#endif
346
db48bcb2
DS
347 int fail = pim_pim_packet(ifp, buf, len);
348 if (fail) {
349 if (PIM_DEBUG_PIM_PACKETS)
350 zlog_debug("%s: pim_pim_packet() return=%d",
351 __PRETTY_FUNCTION__, fail);
352 goto done;
353 }
354
355 count++;
356 if (count % 3 == 0)
357 cont = 0;
358 }
12e41d03
DL
359
360 result = 0; /* good */
361
362 done:
363 pim_sock_read_on(ifp);
364
365 if (result) {
366 ++pim_ifp->pim_ifstat_hello_recvfail;
367 }
368
369 return result;
370}
371
372static void pim_sock_read_on(struct interface *ifp)
373{
374 struct pim_interface *pim_ifp;
375
376 zassert(ifp);
377 zassert(ifp->info);
378
379 pim_ifp = ifp->info;
380
3010e99a 381 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
12e41d03
DL
382 zlog_debug("Scheduling READ event on PIM socket fd=%d",
383 pim_ifp->pim_sock_fd);
384 }
59ba0ac3 385 pim_ifp->t_pim_sock_read = NULL;
12e41d03
DL
386 zassert(!pim_ifp->t_pim_sock_read);
387 THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
388 pim_ifp->pim_sock_fd);
389}
390
b892f1dd 391static int pim_sock_open(struct in_addr ifaddr, ifindex_t ifindex)
12e41d03
DL
392{
393 int fd;
394
61ea3951 395 fd = pim_socket_mcast(IPPROTO_PIM, ifaddr, ifindex, 0 /* loop=false */);
12e41d03
DL
396 if (fd < 0)
397 return -1;
398
399 if (pim_socket_join(fd, qpim_all_pim_routers_addr, ifaddr, ifindex)) {
2cd32c61 400 close(fd);
12e41d03
DL
401 return -2;
402 }
403
404 return fd;
405}
406
407void pim_ifstat_reset(struct interface *ifp)
408{
409 struct pim_interface *pim_ifp;
410
411 zassert(ifp);
412
413 pim_ifp = ifp->info;
414 if (!pim_ifp) {
415 return;
416 }
417
418 pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
419 pim_ifp->pim_ifstat_hello_sent = 0;
420 pim_ifp->pim_ifstat_hello_sendfail = 0;
421 pim_ifp->pim_ifstat_hello_recv = 0;
422 pim_ifp->pim_ifstat_hello_recvfail = 0;
423}
424
425void pim_sock_reset(struct interface *ifp)
426{
427 struct pim_interface *pim_ifp;
428
429 zassert(ifp);
430 zassert(ifp->info);
431
432 pim_ifp = ifp->info;
433
434 pim_ifp->primary_address = pim_find_primary_addr(ifp);
435
436 pim_ifp->pim_sock_fd = -1;
437 pim_ifp->pim_sock_creation = 0;
59ba0ac3 438 pim_ifp->t_pim_sock_read = NULL;
12e41d03 439
59ba0ac3 440 pim_ifp->t_pim_hello_timer = NULL;
12e41d03
DL
441 pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
442 pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
443 pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
444 pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
445 pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
446 pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
447 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
448 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
449 }
450 else {
451 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
452 }
453
454 /* neighbors without lan_delay */
455 pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
456 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
457 pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
458
459 /* DR Election */
460 pim_ifp->pim_dr_election_last = 0; /* timestamp */
461 pim_ifp->pim_dr_election_count = 0;
462 pim_ifp->pim_dr_election_changes = 0;
463 pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */
464 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
465
466 pim_ifstat_reset(ifp);
467}
468
4df01a4e
DS
469static uint16_t ip_id = 0;
470
c305ed63
DS
471
472static int
473pim_msg_send_frame (int fd, char *buf, size_t len,
474 struct sockaddr *dst, size_t salen)
475{
476 struct ip *ip = (struct ip *)buf;
477
478 while (sendto (fd, buf, len, MSG_DONTWAIT, dst, salen) < 0)
479 {
eaa54bdb 480 char dst_str[INET_ADDRSTRLEN];
c305ed63
DS
481
482 switch (errno)
483 {
484 case EMSGSIZE:
485 {
486 size_t hdrsize = sizeof (struct ip);
487 size_t newlen1 = ((len - hdrsize) / 2 ) & 0xFFF8;
488 size_t sendlen = newlen1 + hdrsize;
489 size_t offset = ntohs (ip->ip_off);
490
491 ip->ip_len = htons (sendlen);
492 ip->ip_off = htons (offset | IP_MF);
493 if (pim_msg_send_frame (fd, buf, sendlen, dst, salen) == 0)
494 {
495 struct ip *ip2 = (struct ip *)(buf + newlen1);
496 size_t newlen2 = len - sendlen;
497 sendlen = newlen2 + hdrsize;
498
499 memcpy (ip2, ip, hdrsize);
500 ip2->ip_len = htons (sendlen);
501 ip2->ip_off = htons (offset + (newlen1 >> 3));
502 return pim_msg_send_frame (fd, (char *)ip2, sendlen, dst, salen);
503 }
504 }
505
506 return -1;
507 break;
508 default:
509 pim_inet4_dump ("<dst?>", ip->ip_dst, dst_str, sizeof (dst_str));
510 zlog_warn ("%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
511 __PRETTY_FUNCTION__,
512 dst_str, fd, len,
513 errno, safe_strerror(errno));
c305ed63 514 return -1;
29444f8f 515 break;
c305ed63
DS
516 }
517 }
518
519 return 0;
520}
521
522int
523pim_msg_send(int fd, struct in_addr src,
524 struct in_addr dst, uint8_t *pim_msg,
525 int pim_msg_size, const char *ifname)
12e41d03 526{
12e41d03
DL
527 struct sockaddr_in to;
528 socklen_t tolen;
19e55095 529 unsigned char buffer[10000];
4df01a4e
DS
530 unsigned char *msg_start;
531 struct ip *ip;
532
19e55095 533 memset (buffer, 0, 10000);
4df01a4e
DS
534 int sendlen = sizeof (struct ip) + pim_msg_size;
535
536 msg_start = buffer + sizeof (struct ip);
537 memcpy (msg_start, pim_msg, pim_msg_size);
538
539 ip = (struct ip *)buffer;
540 ip->ip_id = htons (++ip_id);
541 ip->ip_hl = 5;
542 ip->ip_v = 4;
543 ip->ip_p = PIM_IP_PROTO_PIM;
544 ip->ip_src = src;
545 ip->ip_dst = dst;
546 ip->ip_ttl = MAXTTL;
547 ip->ip_len = htons (sendlen);
12e41d03
DL
548
549 if (PIM_DEBUG_PIM_PACKETS) {
eaa54bdb 550 char dst_str[INET_ADDRSTRLEN];
12e41d03
DL
551 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
552 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
553 __PRETTY_FUNCTION__,
554 dst_str, ifname, pim_msg_size,
555 *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg));
556 }
557
12e41d03 558 memset(&to, 0, sizeof(to));
12e41d03
DL
559 to.sin_family = AF_INET;
560 to.sin_addr = dst;
12e41d03
DL
561 tolen = sizeof(to);
562
563 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
564 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
565 }
566
c305ed63
DS
567 pim_msg_send_frame (fd, (char *)buffer, sendlen,
568 (struct sockaddr *)&to, tolen);
12e41d03
DL
569 return 0;
570}
571
572static int hello_send(struct interface *ifp,
573 uint16_t holdtime)
574{
575 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
576 struct pim_interface *pim_ifp;
577 int pim_tlv_size;
578 int pim_msg_size;
579
580 pim_ifp = ifp->info;
581
aea6cb94 582 if (PIM_DEBUG_PIM_HELLO) {
eaa54bdb 583 char dst_str[INET_ADDRSTRLEN];
12e41d03
DL
584 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str));
585 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",
586 __PRETTY_FUNCTION__,
587 dst_str, ifp->name,
588 holdtime,
589 pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec,
590 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
591 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
592 listcount(ifp->connected));
593 }
594
595 pim_tlv_size = pim_hello_build_tlv(ifp->name,
596 pim_msg + PIM_PIM_MIN_LEN,
597 sizeof(pim_msg) - PIM_PIM_MIN_LEN,
598 holdtime,
599 pim_ifp->pim_dr_priority,
600 pim_ifp->pim_generation_id,
601 pim_ifp->pim_propagation_delay_msec,
602 pim_ifp->pim_override_interval_msec,
603 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
604 ifp->connected);
605 if (pim_tlv_size < 0) {
606 return -1;
607 }
608
609 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
610
611 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
612 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
613
614 pim_msg_build_header(pim_msg, pim_msg_size,
615 PIM_MSG_TYPE_HELLO);
616
617 if (pim_msg_send(pim_ifp->pim_sock_fd,
4df01a4e 618 pim_ifp->primary_address,
12e41d03
DL
619 qpim_all_pim_routers_addr,
620 pim_msg,
621 pim_msg_size,
622 ifp->name)) {
aea6cb94
DS
623 if (PIM_DEBUG_PIM_HELLO) {
624 zlog_debug("%s: could not send PIM message on interface %s",
625 __PRETTY_FUNCTION__, ifp->name);
626 }
12e41d03
DL
627 return -2;
628 }
629
630 return 0;
631}
632
633static int pim_hello_send(struct interface *ifp,
634 uint16_t holdtime)
635{
636 struct pim_interface *pim_ifp;
637
638 zassert(ifp);
639 pim_ifp = ifp->info;
640 zassert(pim_ifp);
641
85b62aea
DS
642 if (if_is_loopback (ifp))
643 return 0;
644
12e41d03
DL
645 if (hello_send(ifp, holdtime)) {
646 ++pim_ifp->pim_ifstat_hello_sendfail;
647
aea6cb94
DS
648 if (PIM_DEBUG_PIM_HELLO) {
649 zlog_warn("Could not send PIM hello on interface %s",
650 ifp->name);
651 }
12e41d03
DL
652 return -1;
653 }
654
655 ++pim_ifp->pim_ifstat_hello_sent;
656
657 return 0;
658}
659
660static void hello_resched(struct interface *ifp)
661{
662 struct pim_interface *pim_ifp;
663
664 zassert(ifp);
665 pim_ifp = ifp->info;
666 zassert(pim_ifp);
667
aea6cb94 668 if (PIM_DEBUG_PIM_HELLO) {
12e41d03
DL
669 zlog_debug("Rescheduling %d sec hello on interface %s",
670 pim_ifp->pim_hello_period, ifp->name);
671 }
672 THREAD_OFF(pim_ifp->t_pim_hello_timer);
673 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
674 on_pim_hello_send,
675 ifp, pim_ifp->pim_hello_period);
676}
677
678/*
679 Periodic hello timer
680 */
681static int on_pim_hello_send(struct thread *t)
682{
683 struct pim_interface *pim_ifp;
684 struct interface *ifp;
685
12e41d03 686 ifp = THREAD_ARG(t);
12e41d03
DL
687
688 pim_ifp = ifp->info;
689
690 /*
691 * Schedule next hello
692 */
59ba0ac3 693 pim_ifp->t_pim_hello_timer = NULL;
12e41d03
DL
694 hello_resched(ifp);
695
696 /*
697 * Send hello
698 */
699 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
700}
701
702/*
703 RFC 4601: 4.3.1. Sending Hello Messages
704
705 Thus, if a router needs to send a Join/Prune or Assert message on an
706 interface on which it has not yet sent a Hello message with the
707 currently configured IP address, then it MUST immediately send the
708 relevant Hello message without waiting for the Hello Timer to
709 expire, followed by the Join/Prune or Assert message.
710 */
711void pim_hello_restart_now(struct interface *ifp)
712{
713 struct pim_interface *pim_ifp;
714
715 zassert(ifp);
716 pim_ifp = ifp->info;
717 zassert(pim_ifp);
718
719 /*
720 * Reset next hello timer
721 */
722 hello_resched(ifp);
723
724 /*
725 * Immediately send hello
726 */
727 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
728}
729
730/*
731 RFC 4601: 4.3.1. Sending Hello Messages
732
733 To allow new or rebooting routers to learn of PIM neighbors quickly,
734 when a Hello message is received from a new neighbor, or a Hello
735 message with a new GenID is received from an existing neighbor, a
736 new Hello message should be sent on this interface after a
737 randomized delay between 0 and Triggered_Hello_Delay.
738 */
739void pim_hello_restart_triggered(struct interface *ifp)
740{
741 struct pim_interface *pim_ifp;
742 int triggered_hello_delay_msec;
743 int random_msec;
744
745 zassert(ifp);
746 pim_ifp = ifp->info;
747 zassert(pim_ifp);
748
749 triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
750
751 if (pim_ifp->t_pim_hello_timer) {
752 long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
753 if (remain_msec <= triggered_hello_delay_msec) {
754 /* Rescheduling hello would increase the delay, then it's faster
755 to just wait for the scheduled periodic hello. */
756 return;
757 }
758
759 THREAD_OFF(pim_ifp->t_pim_hello_timer);
59ba0ac3 760 pim_ifp->t_pim_hello_timer = NULL;
12e41d03 761 }
12e41d03 762
60b40924 763 random_msec = random() % (triggered_hello_delay_msec + 1);
12e41d03 764
aea6cb94 765 if (PIM_DEBUG_PIM_HELLO) {
12e41d03
DL
766 zlog_debug("Scheduling %d msec triggered hello on interface %s",
767 random_msec, ifp->name);
768 }
769
770 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
771 on_pim_hello_send,
772 ifp, random_msec);
773}
774
775int pim_sock_add(struct interface *ifp)
776{
777 struct pim_interface *pim_ifp;
778 struct in_addr ifaddr;
c29c0f61 779 uint32_t old_genid;
12e41d03
DL
780
781 pim_ifp = ifp->info;
782 zassert(pim_ifp);
783
784 if (pim_ifp->pim_sock_fd >= 0) {
def1e807
DS
785 if (PIM_DEBUG_PIM_PACKETS)
786 zlog_debug("Can't recreate existing PIM socket fd=%d for interface %s",
787 pim_ifp->pim_sock_fd, ifp->name);
12e41d03
DL
788 return -1;
789 }
790
791 ifaddr = pim_ifp->primary_address;
792
793 pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
794 if (pim_ifp->pim_sock_fd < 0) {
def1e807
DS
795 if (PIM_DEBUG_PIM_PACKETS)
796 zlog_debug("Could not open PIM socket on interface %s",
797 ifp->name);
12e41d03
DL
798 return -2;
799 }
800
4df01a4e
DS
801 pim_socket_ip_hdr (pim_ifp->pim_sock_fd);
802
59ba0ac3 803 pim_ifp->t_pim_sock_read = NULL;
12e41d03
DL
804 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
805
c29c0f61
DS
806 /*
807 * Just ensure that the new generation id
808 * actually chooses something different.
809 * Actually ran across a case where this
810 * happened, pre-switch to random().
811 * While this is unlikely to happen now
812 * let's make sure it doesn't.
813 */
814 old_genid = pim_ifp->pim_generation_id;
815
816 while (old_genid == pim_ifp->pim_generation_id)
817 pim_ifp->pim_generation_id = random();
12e41d03
DL
818
819 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
820 ifp->name, ifp->ifindex);
821
822 /*
823 * Start receiving PIM messages
824 */
825 pim_sock_read_on(ifp);
826
827 /*
828 * Start sending PIM hello's
829 */
830 pim_hello_restart_triggered(ifp);
831
832 return 0;
833}