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