]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_pim.c
bgpd: Accept no aggregate-address <IP> route-map <RMAP> commands
[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) {
193 /* First 8 byte header checksum */
194 checksum = in_cksum(pim_msg, PIM_MSG_REGISTER_LEN);
195 if (checksum != pim_checksum) {
196 checksum = in_cksum(pim_msg, pim_msg_len);
197 if (checksum != pim_checksum) {
198 if (PIM_DEBUG_PIM_PACKETS)
199 zlog_debug(
200 "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
201 ifp->name, pim_checksum,
202 checksum);
203
204 return -1;
205 }
206 }
207 } else {
208 checksum = in_cksum(pim_msg, pim_msg_len);
209 if (checksum != pim_checksum) {
210 if (PIM_DEBUG_PIM_PACKETS)
211 zlog_debug(
212 "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
213 ifp->name, pim_checksum, checksum);
214
215 return -1;
216 }
217 }
218
219 if (PIM_DEBUG_PIM_PACKETS) {
220 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str,
221 sizeof(src_str));
222 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str,
223 sizeof(dst_str));
224 zlog_debug(
225 "Recv PIM %s packet from %s to %s on %s: ttl=%d pim_version=%d pim_msg_size=%d checksum=%x",
226 pim_pim_msgtype2str(header->type), src_str, dst_str,
227 ifp->name, ip_hdr->ip_ttl, header->ver, pim_msg_len,
228 checksum);
229 if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
230 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
231 }
232 }
233
234 switch (header->type) {
235 case PIM_MSG_TYPE_HELLO:
236 return pim_hello_recv(ifp, ip_hdr->ip_src,
237 pim_msg + PIM_MSG_HEADER_LEN,
238 pim_msg_len - PIM_MSG_HEADER_LEN);
239 break;
240 case PIM_MSG_TYPE_REGISTER:
241 return pim_register_recv(ifp, ip_hdr->ip_dst, ip_hdr->ip_src,
242 pim_msg + PIM_MSG_HEADER_LEN,
243 pim_msg_len - PIM_MSG_HEADER_LEN);
244 break;
245 case PIM_MSG_TYPE_REG_STOP:
b206566b 246 return pim_register_stop_recv(ifp, pim_msg + PIM_MSG_HEADER_LEN,
d62a17ae 247 pim_msg_len - PIM_MSG_HEADER_LEN);
248 break;
249 case PIM_MSG_TYPE_JOIN_PRUNE:
250 neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
251 if (!neigh) {
252 if (PIM_DEBUG_PIM_PACKETS)
253 zlog_debug(
254 "%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
255 __FILE__, __PRETTY_FUNCTION__,
256 header->type, src_str, ifp->name);
257 return -1;
258 }
259 pim_neighbor_timer_reset(neigh, neigh->holdtime);
260 return pim_joinprune_recv(ifp, neigh, ip_hdr->ip_src,
261 pim_msg + PIM_MSG_HEADER_LEN,
262 pim_msg_len - PIM_MSG_HEADER_LEN);
263 break;
264 case PIM_MSG_TYPE_ASSERT:
265 neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
266 if (!neigh) {
267 if (PIM_DEBUG_PIM_PACKETS)
268 zlog_debug(
269 "%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
270 __FILE__, __PRETTY_FUNCTION__,
271 header->type, src_str, ifp->name);
272 return -1;
273 }
274 pim_neighbor_timer_reset(neigh, neigh->holdtime);
275 return pim_assert_recv(ifp, neigh, ip_hdr->ip_src,
276 pim_msg + PIM_MSG_HEADER_LEN,
277 pim_msg_len - PIM_MSG_HEADER_LEN);
278 break;
5acde1cf 279 case PIM_MSG_TYPE_BOOTSTRAP:
280 return pim_bsm_process(ifp, ip_hdr, pim_msg, pim_msg_len,
281 no_fwd);
282 break;
d57a8bbf 283
d62a17ae 284 default:
285 if (PIM_DEBUG_PIM_PACKETS) {
286 zlog_debug(
287 "Recv PIM packet type %d which is not currently understood",
288 header->type);
289 }
290 return -1;
291 }
4dffc880 292 return -1;
12e41d03
DL
293}
294
295static void pim_sock_read_on(struct interface *ifp);
296
297static int pim_sock_read(struct thread *t)
298{
9487552c 299 struct interface *ifp, *orig_ifp;
d62a17ae 300 struct pim_interface *pim_ifp;
301 int fd;
302 struct sockaddr_in from;
303 struct sockaddr_in to;
304 socklen_t fromlen = sizeof(from);
305 socklen_t tolen = sizeof(to);
306 uint8_t buf[PIM_PIM_BUFSIZE_READ];
307 int len;
308 ifindex_t ifindex = -1;
309 int result = -1; /* defaults to bad */
310 static long long count = 0;
311 int cont = 1;
312
9487552c 313 orig_ifp = ifp = THREAD_ARG(t);
d62a17ae 314 fd = THREAD_FD(t);
315
316 pim_ifp = ifp->info;
317
318 while (cont) {
319 len = pim_socket_recvfromto(fd, buf, sizeof(buf), &from,
320 &fromlen, &to, &tolen, &ifindex);
321 if (len < 0) {
322 if (errno == EINTR)
323 continue;
324 if (errno == EWOULDBLOCK || errno == EAGAIN)
325 break;
326
327 if (PIM_DEBUG_PIM_PACKETS)
328 zlog_debug("Received errno: %d %s", errno,
329 safe_strerror(errno));
330 goto done;
331 }
12e41d03 332
e2d451e2
DS
333 /*
334 * What? So with vrf's the incoming packet is received
335 * on the vrf interface but recvfromto above returns
336 * the right ifindex, so just use it. We know
337 * it's the right interface because we bind to it
338 */
339 ifp = if_lookup_by_index(ifindex, pim_ifp->pim->vrf_id);
05d8470f 340 if (!ifp || !ifp->info) {
a5b6bd2b
DS
341 if (PIM_DEBUG_PIM_PACKETS)
342 zlog_debug(
8cd38306
DS
343 "%s: Received incoming pim packet on interface(%s:%d) not yet configured for pim",
344 __PRETTY_FUNCTION__,
345 ifp ? ifp->name : "Unknown", ifindex);
a5b6bd2b
DS
346 goto done;
347 }
d62a17ae 348 int fail = pim_pim_packet(ifp, buf, len);
349 if (fail) {
350 if (PIM_DEBUG_PIM_PACKETS)
351 zlog_debug("%s: pim_pim_packet() return=%d",
352 __PRETTY_FUNCTION__, fail);
353 goto done;
354 }
355
356 count++;
75373cca 357 if (count % router->packet_process == 0)
d62a17ae 358 cont = 0;
359 }
12e41d03 360
d62a17ae 361 result = 0; /* good */
12e41d03 362
d62a17ae 363done:
9487552c 364 pim_sock_read_on(orig_ifp);
12e41d03 365
d62a17ae 366 if (result) {
367 ++pim_ifp->pim_ifstat_hello_recvfail;
368 }
12e41d03 369
d62a17ae 370 return result;
12e41d03
DL
371}
372
373static void pim_sock_read_on(struct interface *ifp)
374{
d62a17ae 375 struct pim_interface *pim_ifp;
12e41d03 376
d62a17ae 377 zassert(ifp);
378 zassert(ifp->info);
12e41d03 379
d62a17ae 380 pim_ifp = ifp->info;
12e41d03 381
d62a17ae 382 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
383 zlog_debug("Scheduling READ event on PIM socket fd=%d",
384 pim_ifp->pim_sock_fd);
385 }
386 pim_ifp->t_pim_sock_read = NULL;
36417fcc
DS
387 thread_add_read(router->master, pim_sock_read, ifp,
388 pim_ifp->pim_sock_fd, &pim_ifp->t_pim_sock_read);
12e41d03
DL
389}
390
e5dfe687 391static int pim_sock_open(struct interface *ifp)
12e41d03 392{
d62a17ae 393 int fd;
394 struct pim_interface *pim_ifp = ifp->info;
395
396 fd = pim_socket_mcast(IPPROTO_PIM, pim_ifp->primary_address, ifp,
397 0 /* loop=false */);
398 if (fd < 0)
399 return -1;
400
401 if (pim_socket_join(fd, qpim_all_pim_routers_addr,
402 pim_ifp->primary_address, ifp->ifindex)) {
403 close(fd);
404 return -2;
405 }
12e41d03 406
d62a17ae 407 return fd;
12e41d03
DL
408}
409
410void pim_ifstat_reset(struct interface *ifp)
411{
d62a17ae 412 struct pim_interface *pim_ifp;
12e41d03 413
d62a17ae 414 zassert(ifp);
12e41d03 415
d62a17ae 416 pim_ifp = ifp->info;
417 if (!pim_ifp) {
418 return;
419 }
12e41d03 420
d62a17ae 421 pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
422 pim_ifp->pim_ifstat_hello_sent = 0;
423 pim_ifp->pim_ifstat_hello_sendfail = 0;
424 pim_ifp->pim_ifstat_hello_recv = 0;
425 pim_ifp->pim_ifstat_hello_recvfail = 0;
12e41d03
DL
426}
427
428void pim_sock_reset(struct interface *ifp)
429{
d62a17ae 430 struct pim_interface *pim_ifp;
431
432 zassert(ifp);
433 zassert(ifp->info);
434
435 pim_ifp = ifp->info;
436
437 pim_ifp->primary_address = pim_find_primary_addr(ifp);
438
439 pim_ifp->pim_sock_fd = -1;
440 pim_ifp->pim_sock_creation = 0;
441 pim_ifp->t_pim_sock_read = NULL;
442
443 pim_ifp->t_pim_hello_timer = NULL;
444 pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
445 pim_ifp->pim_default_holdtime =
446 -1; /* unset: means 3.5 * pim_hello_period */
447 pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
448 pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
449 pim_ifp->pim_propagation_delay_msec =
450 PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
451 pim_ifp->pim_override_interval_msec =
452 PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
453 if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
454 PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
455 } else {
456 PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
457 }
458
459 /* neighbors without lan_delay */
460 pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
461 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
462 pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
463
464 /* DR Election */
465 pim_ifp->pim_dr_election_last = 0; /* timestamp */
466 pim_ifp->pim_dr_election_count = 0;
467 pim_ifp->pim_dr_election_changes = 0;
468 pim_ifp->pim_dr_num_nondrpri_neighbors =
469 0; /* neighbors without dr_pri */
470 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
471
472 pim_ifstat_reset(ifp);
12e41d03
DL
473}
474
4df01a4e
DS
475static uint16_t ip_id = 0;
476
c305ed63 477
d62a17ae 478static int pim_msg_send_frame(int fd, char *buf, size_t len,
479 struct sockaddr *dst, size_t salen)
c305ed63 480{
d62a17ae 481 struct ip *ip = (struct ip *)buf;
482
483 while (sendto(fd, buf, len, MSG_DONTWAIT, dst, salen) < 0) {
484 char dst_str[INET_ADDRSTRLEN];
485
486 switch (errno) {
487 case EMSGSIZE: {
488 size_t hdrsize = sizeof(struct ip);
489 size_t newlen1 = ((len - hdrsize) / 2) & 0xFFF8;
490 size_t sendlen = newlen1 + hdrsize;
491 size_t offset = ntohs(ip->ip_off);
492
493 ip->ip_len = htons(sendlen);
494 ip->ip_off = htons(offset | IP_MF);
495 if (pim_msg_send_frame(fd, buf, sendlen, dst, salen)
496 == 0) {
497 struct ip *ip2 = (struct ip *)(buf + newlen1);
498 size_t newlen2 = len - sendlen;
499 sendlen = newlen2 + hdrsize;
500
501 memcpy(ip2, ip, hdrsize);
502 ip2->ip_len = htons(sendlen);
503 ip2->ip_off = htons(offset + (newlen1 >> 3));
504 return pim_msg_send_frame(fd, (char *)ip2,
505 sendlen, dst, salen);
506 }
507 }
508
509 return -1;
510 break;
511 default:
512 if (PIM_DEBUG_PIM_PACKETS) {
513 pim_inet4_dump("<dst?>", ip->ip_dst, dst_str,
514 sizeof(dst_str));
515 zlog_warn(
516 "%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
517 __PRETTY_FUNCTION__, dst_str, fd, len,
518 errno, safe_strerror(errno));
519 }
520 return -1;
521 break;
522 }
c305ed63 523 }
c305ed63 524
d62a17ae 525 return 0;
c305ed63
DS
526}
527
d62a17ae 528int pim_msg_send(int fd, struct in_addr src, struct in_addr dst,
529 uint8_t *pim_msg, int pim_msg_size, const char *ifname)
12e41d03 530{
d62a17ae 531 struct sockaddr_in to;
532 socklen_t tolen;
533 unsigned char buffer[10000];
534 unsigned char *msg_start;
a2b6e694 535 uint8_t ttl;
d62a17ae 536 struct pim_msg_header *header;
537 struct ip *ip;
538
539 memset(buffer, 0, 10000);
540 int sendlen = sizeof(struct ip) + pim_msg_size;
541
542 msg_start = buffer + sizeof(struct ip);
543 memcpy(msg_start, pim_msg, pim_msg_size);
544
545 header = (struct pim_msg_header *)pim_msg;
546/*
547 * Omnios apparently doesn't have a #define for IP default
548 * ttl that is the same as all other platforms.
549 */
05ea5cee
DS
550#ifndef IPDEFTTL
551#define IPDEFTTL 64
552#endif
d62a17ae 553 /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
554 switch (header->type) {
555 case PIM_MSG_TYPE_HELLO:
556 case PIM_MSG_TYPE_JOIN_PRUNE:
557 case PIM_MSG_TYPE_BOOTSTRAP:
558 case PIM_MSG_TYPE_ASSERT:
559 ttl = 1;
560 break;
561 case PIM_MSG_TYPE_REGISTER:
562 case PIM_MSG_TYPE_REG_STOP:
563 case PIM_MSG_TYPE_GRAFT:
564 case PIM_MSG_TYPE_GRAFT_ACK:
565 case PIM_MSG_TYPE_CANDIDATE:
566 ttl = IPDEFTTL;
567 break;
568 default:
569 ttl = MAXTTL;
570 break;
571 }
572
573 ip = (struct ip *)buffer;
574 ip->ip_id = htons(++ip_id);
575 ip->ip_hl = 5;
576 ip->ip_v = 4;
577 ip->ip_p = PIM_IP_PROTO_PIM;
578 ip->ip_src = src;
579 ip->ip_dst = dst;
580 ip->ip_ttl = ttl;
581 ip->ip_len = htons(sendlen);
582
583 if (PIM_DEBUG_PIM_PACKETS) {
d62a17ae 584 char dst_str[INET_ADDRSTRLEN];
585 pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
586 zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
587 __PRETTY_FUNCTION__, dst_str, ifname, pim_msg_size,
588 header->checksum);
589 }
590
591 memset(&to, 0, sizeof(to));
592 to.sin_family = AF_INET;
593 to.sin_addr = dst;
594 tolen = sizeof(to);
595
596 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
597 pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
598 }
599
600 pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to,
601 tolen);
602 return 0;
12e41d03
DL
603}
604
d62a17ae 605static int hello_send(struct interface *ifp, uint16_t holdtime)
12e41d03 606{
d62a17ae 607 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
608 struct pim_interface *pim_ifp;
609 int pim_tlv_size;
610 int pim_msg_size;
611
612 pim_ifp = ifp->info;
613
614 if (PIM_DEBUG_PIM_HELLO) {
615 char dst_str[INET_ADDRSTRLEN];
616 pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str,
617 sizeof(dst_str));
618 zlog_debug(
619 "%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",
620 __PRETTY_FUNCTION__, dst_str, ifp->name, holdtime,
621 pim_ifp->pim_propagation_delay_msec,
622 pim_ifp->pim_override_interval_msec,
623 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(
624 pim_ifp->options),
625 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
626 listcount(ifp->connected));
627 }
628
629 pim_tlv_size = pim_hello_build_tlv(
630 ifp, pim_msg + PIM_PIM_MIN_LEN,
631 sizeof(pim_msg) - PIM_PIM_MIN_LEN, holdtime,
632 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
633 pim_ifp->pim_propagation_delay_msec,
634 pim_ifp->pim_override_interval_msec,
635 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options));
636 if (pim_tlv_size < 0) {
637 return -1;
638 }
639
640 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
641
642 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
643 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
644
d57a8bbf 645 pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO, false);
d62a17ae 646
647 if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
648 qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
649 ifp->name)) {
650 if (PIM_DEBUG_PIM_HELLO) {
651 zlog_debug(
652 "%s: could not send PIM message on interface %s",
653 __PRETTY_FUNCTION__, ifp->name);
654 }
655 return -2;
656 }
657
658 return 0;
12e41d03
DL
659}
660
d62a17ae 661static int pim_hello_send(struct interface *ifp, uint16_t holdtime)
12e41d03 662{
11699c47 663 struct pim_interface *pim_ifp = ifp->info;
12e41d03 664
fec4ca19 665 if (if_is_loopback_or_vrf(ifp))
d62a17ae 666 return 0;
85b62aea 667
d62a17ae 668 if (hello_send(ifp, holdtime)) {
669 ++pim_ifp->pim_ifstat_hello_sendfail;
12e41d03 670
d62a17ae 671 if (PIM_DEBUG_PIM_HELLO) {
672 zlog_warn("Could not send PIM hello on interface %s",
673 ifp->name);
674 }
675 return -1;
676 }
12e41d03 677
d62a17ae 678 ++pim_ifp->pim_ifstat_hello_sent;
12e41d03 679
d62a17ae 680 return 0;
12e41d03
DL
681}
682
683static void hello_resched(struct interface *ifp)
684{
d62a17ae 685 struct pim_interface *pim_ifp;
686
d62a17ae 687 pim_ifp = ifp->info;
d62a17ae 688
689 if (PIM_DEBUG_PIM_HELLO) {
690 zlog_debug("Rescheduling %d sec hello on interface %s",
691 pim_ifp->pim_hello_period, ifp->name);
692 }
693 THREAD_OFF(pim_ifp->t_pim_hello_timer);
36417fcc 694 thread_add_timer(router->master, on_pim_hello_send, ifp,
d62a17ae 695 pim_ifp->pim_hello_period,
696 &pim_ifp->t_pim_hello_timer);
12e41d03
DL
697}
698
699/*
700 Periodic hello timer
701 */
702static int on_pim_hello_send(struct thread *t)
703{
d62a17ae 704 struct pim_interface *pim_ifp;
705 struct interface *ifp;
12e41d03 706
d62a17ae 707 ifp = THREAD_ARG(t);
d62a17ae 708 pim_ifp = ifp->info;
12e41d03 709
d62a17ae 710 /*
711 * Schedule next hello
712 */
713 hello_resched(ifp);
12e41d03 714
d62a17ae 715 /*
716 * Send hello
717 */
718 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
12e41d03
DL
719}
720
721/*
722 RFC 4601: 4.3.1. Sending Hello Messages
723
724 Thus, if a router needs to send a Join/Prune or Assert message on an
725 interface on which it has not yet sent a Hello message with the
726 currently configured IP address, then it MUST immediately send the
727 relevant Hello message without waiting for the Hello Timer to
728 expire, followed by the Join/Prune or Assert message.
729 */
730void pim_hello_restart_now(struct interface *ifp)
731{
d62a17ae 732 struct pim_interface *pim_ifp;
12e41d03 733
d62a17ae 734 pim_ifp = ifp->info;
12e41d03 735
d62a17ae 736 /*
737 * Reset next hello timer
738 */
739 hello_resched(ifp);
12e41d03 740
d62a17ae 741 /*
742 * Immediately send hello
743 */
744 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
12e41d03
DL
745}
746
747/*
748 RFC 4601: 4.3.1. Sending Hello Messages
749
750 To allow new or rebooting routers to learn of PIM neighbors quickly,
751 when a Hello message is received from a new neighbor, or a Hello
752 message with a new GenID is received from an existing neighbor, a
753 new Hello message should be sent on this interface after a
754 randomized delay between 0 and Triggered_Hello_Delay.
755 */
756void pim_hello_restart_triggered(struct interface *ifp)
757{
d62a17ae 758 struct pim_interface *pim_ifp;
759 int triggered_hello_delay_msec;
760 int random_msec;
761
d62a17ae 762 pim_ifp = ifp->info;
2aa1ca84
DS
763
764 /*
765 * No need to ever start loopback or vrf device hello's
766 */
fec4ca19 767 if (if_is_loopback_or_vrf(ifp))
2aa1ca84 768 return;
d62a17ae 769
770 /*
771 * There exists situations where we have the a RPF out this
772 * interface, but we haven't formed a neighbor yet. This
773 * happens especially during interface flaps. While
774 * we would like to handle this more gracefully in other
775 * parts of the code. In order to get us up and running
776 * let's just send the hello immediate'ish
777 * This should be revisited when we get nexthop tracking
778 * in and when we have a better handle on safely
779 * handling the rpf information for upstreams that
780 * we cannot legally reach yet.
781 */
782 triggered_hello_delay_msec = 1;
783 // triggered_hello_delay_msec = 1000 *
784 // pim_ifp->pim_triggered_hello_delay;
785
786 if (pim_ifp->t_pim_hello_timer) {
787 long remain_msec =
788 pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
789 if (remain_msec <= triggered_hello_delay_msec) {
790 /* Rescheduling hello would increase the delay, then
791 it's faster
792 to just wait for the scheduled periodic hello. */
793 return;
794 }
795
796 THREAD_OFF(pim_ifp->t_pim_hello_timer);
797 }
798
799 random_msec = triggered_hello_delay_msec;
800 // random_msec = random() % (triggered_hello_delay_msec + 1);
801
802 if (PIM_DEBUG_PIM_HELLO) {
803 zlog_debug("Scheduling %d msec triggered hello on interface %s",
804 random_msec, ifp->name);
805 }
806
36417fcc
DS
807 thread_add_timer_msec(router->master, on_pim_hello_send, ifp,
808 random_msec, &pim_ifp->t_pim_hello_timer);
12e41d03
DL
809}
810
811int pim_sock_add(struct interface *ifp)
812{
d62a17ae 813 struct pim_interface *pim_ifp;
814 uint32_t old_genid;
815
816 pim_ifp = ifp->info;
817 zassert(pim_ifp);
818
819 if (pim_ifp->pim_sock_fd >= 0) {
820 if (PIM_DEBUG_PIM_PACKETS)
821 zlog_debug(
822 "Can't recreate existing PIM socket fd=%d for interface %s",
823 pim_ifp->pim_sock_fd, ifp->name);
824 return -1;
825 }
826
827 pim_ifp->pim_sock_fd = pim_sock_open(ifp);
828 if (pim_ifp->pim_sock_fd < 0) {
829 if (PIM_DEBUG_PIM_PACKETS)
830 zlog_debug("Could not open PIM socket on interface %s",
831 ifp->name);
832 return -2;
833 }
834
835 pim_socket_ip_hdr(pim_ifp->pim_sock_fd);
836
837 pim_ifp->t_pim_sock_read = NULL;
838 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
839
840 /*
841 * Just ensure that the new generation id
842 * actually chooses something different.
843 * Actually ran across a case where this
844 * happened, pre-switch to random().
845 * While this is unlikely to happen now
846 * let's make sure it doesn't.
847 */
848 old_genid = pim_ifp->pim_generation_id;
849
850 while (old_genid == pim_ifp->pim_generation_id)
851 pim_ifp->pim_generation_id = random();
852
853 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp->name,
854 ifp->ifindex);
855
856 /*
857 * Start receiving PIM messages
858 */
859 pim_sock_read_on(ifp);
860
861 /*
862 * Start sending PIM hello's
863 */
864 pim_hello_restart_triggered(ifp);
865
866 return 0;
12e41d03 867}