]> git.proxmox.com Git - mirror_frr.git/blame_incremental - pimd/pim_pim.c
bgpd: fix the IGP metric for best path selection on VPN import
[mirror_frr.git] / pimd / pim_pim.c
... / ...
CommitLineData
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 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 */
19
20#include <zebra.h>
21
22#include "log.h"
23#include "thread.h"
24#include "memory.h"
25#include "if.h"
26#include "network.h"
27
28#include "pimd.h"
29#include "pim_instance.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"
42#include "pim_register.h"
43#include "pim_errors.h"
44#include "pim_bsm.h"
45#include <lib/lib_errors.h>
46
47static void on_pim_hello_send(struct thread *t);
48
49static const char *pim_pim_msgtype2str(enum pim_msg_type type)
50{
51 switch (type) {
52 case PIM_MSG_TYPE_HELLO:
53 return "HELLO";
54 case PIM_MSG_TYPE_REGISTER:
55 return "REGISTER";
56 case PIM_MSG_TYPE_REG_STOP:
57 return "REGSTOP";
58 case PIM_MSG_TYPE_JOIN_PRUNE:
59 return "JOINPRUNE";
60 case PIM_MSG_TYPE_BOOTSTRAP:
61 return "BOOT";
62 case PIM_MSG_TYPE_ASSERT:
63 return "ASSERT";
64 case PIM_MSG_TYPE_GRAFT:
65 return "GRAFT";
66 case PIM_MSG_TYPE_GRAFT_ACK:
67 return "GACK";
68 case PIM_MSG_TYPE_CANDIDATE:
69 return "CANDIDATE";
70 }
71
72 return "UNKNOWN";
73}
74
75static void sock_close(struct interface *ifp)
76{
77 struct pim_interface *pim_ifp = ifp->info;
78
79 if (PIM_DEBUG_PIM_TRACE) {
80 if (pim_ifp->t_pim_sock_read) {
81 zlog_debug(
82 "Cancelling READ event for PIM socket fd=%d on interface %s",
83 pim_ifp->pim_sock_fd, ifp->name);
84 }
85 }
86 THREAD_OFF(pim_ifp->t_pim_sock_read);
87
88 if (PIM_DEBUG_PIM_TRACE) {
89 if (pim_ifp->t_pim_hello_timer) {
90 zlog_debug(
91 "Cancelling PIM hello timer for interface %s",
92 ifp->name);
93 }
94 }
95 THREAD_OFF(pim_ifp->t_pim_hello_timer);
96
97 if (PIM_DEBUG_PIM_TRACE) {
98 zlog_debug("Deleting PIM socket fd=%d on interface %s",
99 pim_ifp->pim_sock_fd, ifp->name);
100 }
101
102 /*
103 * If the fd is already deleted no need to do anything here
104 */
105 if (pim_ifp->pim_sock_fd > 0 && close(pim_ifp->pim_sock_fd)) {
106 zlog_warn(
107 "Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
108 pim_ifp->pim_sock_fd, ifp->name, errno,
109 safe_strerror(errno));
110 }
111
112 pim_ifp->pim_sock_fd = -1;
113 pim_ifp->pim_sock_creation = 0;
114}
115
116void pim_sock_delete(struct interface *ifp, const char *delete_message)
117{
118 zlog_info("PIM INTERFACE DOWN: on interface %s: %s", ifp->name,
119 delete_message);
120
121 if (!ifp->info) {
122 flog_err(EC_PIM_CONFIG,
123 "%s: %s: but PIM not enabled on interface %s (!)",
124 __func__, delete_message, ifp->name);
125 return;
126 }
127
128 /*
129 RFC 4601: 4.3.1. Sending Hello Messages
130
131 Before an interface goes down or changes primary IP address, a Hello
132 message with a zero HoldTime should be sent immediately (with the
133 old IP address if the IP address changed).
134 */
135 pim_hello_send(ifp, 0 /* zero-sec holdtime */);
136
137 pim_neighbor_delete_all(ifp, delete_message);
138
139 sock_close(ifp);
140}
141
142/* For now check dst address for hello, assrt and join/prune is all pim rtr */
143static bool pim_pkt_dst_addr_ok(enum pim_msg_type type, pim_addr addr)
144{
145 if ((type == PIM_MSG_TYPE_HELLO) || (type == PIM_MSG_TYPE_ASSERT)
146 || (type == PIM_MSG_TYPE_JOIN_PRUNE)) {
147 if (pim_addr_cmp(addr, qpim_all_pim_routers_addr))
148 return false;
149 }
150
151 return true;
152}
153
154int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
155 pim_sgaddr sg)
156{
157 struct iovec iov[2], *iovp = iov;
158#if PIM_IPV == 4
159 struct ip *ip_hdr = (struct ip *)buf;
160 size_t ip_hlen; /* ip header length in bytes */
161#endif
162 uint8_t *pim_msg;
163 uint32_t pim_msg_len = 0;
164 uint16_t pim_checksum; /* received checksum */
165 uint16_t checksum; /* computed checksum */
166 struct pim_neighbor *neigh;
167 struct pim_msg_header *header;
168 bool no_fwd;
169
170#if PIM_IPV == 4
171 if (len < sizeof(*ip_hdr)) {
172 if (PIM_DEBUG_PIM_PACKETS)
173 zlog_debug(
174 "PIM packet size=%zu shorter than minimum=%zu",
175 len, sizeof(*ip_hdr));
176 return -1;
177 }
178
179 ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
180 sg = pim_sgaddr_from_iphdr(ip_hdr);
181
182 pim_msg = buf + ip_hlen;
183 pim_msg_len = len - ip_hlen;
184#else
185 struct ipv6_ph phdr = {
186 .src = sg.src,
187 .dst = sg.grp,
188 .ulpl = htonl(len),
189 .next_hdr = IPPROTO_PIM,
190 };
191
192 iovp->iov_base = &phdr;
193 iovp->iov_len = sizeof(phdr);
194 iovp++;
195
196 /* NB: header is not included in IPv6 RX */
197 pim_msg = buf;
198 pim_msg_len = len;
199#endif
200
201 iovp->iov_base = pim_msg;
202 iovp->iov_len = pim_msg_len;
203 iovp++;
204
205 header = (struct pim_msg_header *)pim_msg;
206 if (pim_msg_len < PIM_PIM_MIN_LEN) {
207 if (PIM_DEBUG_PIM_PACKETS)
208 zlog_debug(
209 "PIM message size=%d shorter than minimum=%d",
210 pim_msg_len, PIM_PIM_MIN_LEN);
211 return -1;
212 }
213
214 if (header->ver != PIM_PROTO_VERSION) {
215 if (PIM_DEBUG_PIM_PACKETS)
216 zlog_debug(
217 "Ignoring PIM pkt from %s with unsupported version: %d",
218 ifp->name, header->ver);
219 return -1;
220 }
221
222 /* save received checksum */
223 pim_checksum = header->checksum;
224
225 /* for computing checksum */
226 header->checksum = 0;
227 no_fwd = header->Nbit;
228
229 if (header->type == PIM_MSG_TYPE_REGISTER) {
230 if (pim_msg_len < PIM_MSG_REGISTER_LEN) {
231 if (PIM_DEBUG_PIM_PACKETS)
232 zlog_debug("PIM Register Message size=%d shorther than min length %d",
233 pim_msg_len, PIM_MSG_REGISTER_LEN);
234 return -1;
235 }
236
237#if PIM_IPV == 6
238 phdr.ulpl = htonl(PIM_MSG_REGISTER_LEN);
239#endif
240 /* First 8 byte header checksum */
241 iovp[-1].iov_len = PIM_MSG_REGISTER_LEN;
242 checksum = in_cksumv(iov, iovp - iov);
243
244 if (checksum != pim_checksum) {
245#if PIM_IPV == 6
246 phdr.ulpl = htonl(pim_msg_len);
247#endif
248 iovp[-1].iov_len = pim_msg_len;
249
250 checksum = in_cksumv(iov, iovp - iov);
251 if (checksum != pim_checksum) {
252 if (PIM_DEBUG_PIM_PACKETS)
253 zlog_debug(
254 "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
255 ifp->name, pim_checksum,
256 checksum);
257
258 return -1;
259 }
260 }
261 } else {
262 checksum = in_cksumv(iov, iovp - iov);
263 if (checksum != pim_checksum) {
264 if (PIM_DEBUG_PIM_PACKETS)
265 zlog_debug(
266 "Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
267 ifp->name, pim_checksum, checksum);
268
269 return -1;
270 }
271 }
272
273 if (PIM_DEBUG_PIM_PACKETS) {
274 zlog_debug(
275 "Recv PIM %s packet from %pPA to %pPA on %s: pim_version=%d pim_msg_size=%d checksum=%x",
276 pim_pim_msgtype2str(header->type), &sg.src, &sg.grp,
277 ifp->name, header->ver, pim_msg_len, checksum);
278 if (PIM_DEBUG_PIM_PACKETDUMP_RECV)
279 pim_pkt_dump(__func__, pim_msg, pim_msg_len);
280 }
281
282 if (!pim_pkt_dst_addr_ok(header->type, sg.grp)) {
283 zlog_warn(
284 "%s: Ignoring Pkt. Unexpected IP destination %pPA for %s (Expected: all_pim_routers_addr) from %pPA",
285 __func__, &sg.grp, pim_pim_msgtype2str(header->type),
286 &sg.src);
287 return -1;
288 }
289
290 switch (header->type) {
291 case PIM_MSG_TYPE_HELLO:
292 return pim_hello_recv(ifp, sg.src, pim_msg + PIM_MSG_HEADER_LEN,
293 pim_msg_len - PIM_MSG_HEADER_LEN);
294 break;
295 case PIM_MSG_TYPE_REGISTER:
296 return pim_register_recv(ifp, sg.grp, sg.src,
297 pim_msg + PIM_MSG_HEADER_LEN,
298 pim_msg_len - PIM_MSG_HEADER_LEN);
299 break;
300 case PIM_MSG_TYPE_REG_STOP:
301 return pim_register_stop_recv(ifp, pim_msg + PIM_MSG_HEADER_LEN,
302 pim_msg_len - PIM_MSG_HEADER_LEN);
303 break;
304 case PIM_MSG_TYPE_JOIN_PRUNE:
305 neigh = pim_neighbor_find(ifp, sg.src);
306 if (!neigh) {
307 if (PIM_DEBUG_PIM_PACKETS)
308 zlog_debug(
309 "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
310 __FILE__, __func__, header->type,
311 &sg.src, ifp->name);
312 return -1;
313 }
314 pim_neighbor_timer_reset(neigh, neigh->holdtime);
315 return pim_joinprune_recv(ifp, neigh, sg.src,
316 pim_msg + PIM_MSG_HEADER_LEN,
317 pim_msg_len - PIM_MSG_HEADER_LEN);
318 break;
319 case PIM_MSG_TYPE_ASSERT:
320 neigh = pim_neighbor_find(ifp, sg.src);
321 if (!neigh) {
322 if (PIM_DEBUG_PIM_PACKETS)
323 zlog_debug(
324 "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
325 __FILE__, __func__, header->type,
326 &sg.src, ifp->name);
327 return -1;
328 }
329 pim_neighbor_timer_reset(neigh, neigh->holdtime);
330 return pim_assert_recv(ifp, neigh, sg.src,
331 pim_msg + PIM_MSG_HEADER_LEN,
332 pim_msg_len - PIM_MSG_HEADER_LEN);
333 break;
334 case PIM_MSG_TYPE_BOOTSTRAP:
335 return pim_bsm_process(ifp, &sg, pim_msg, pim_msg_len, no_fwd);
336 break;
337
338 default:
339 if (PIM_DEBUG_PIM_PACKETS) {
340 zlog_debug(
341 "Recv PIM packet type %d which is not currently understood",
342 header->type);
343 }
344 return -1;
345 }
346}
347
348static void pim_sock_read_on(struct interface *ifp);
349
350static void pim_sock_read(struct thread *t)
351{
352 struct interface *ifp, *orig_ifp;
353 struct pim_interface *pim_ifp;
354 int fd;
355 struct sockaddr_storage from;
356 struct sockaddr_storage to;
357 socklen_t fromlen = sizeof(from);
358 socklen_t tolen = sizeof(to);
359 uint8_t buf[PIM_PIM_BUFSIZE_READ];
360 int len;
361 ifindex_t ifindex = -1;
362 int result = -1; /* defaults to bad */
363 static long long count = 0;
364 int cont = 1;
365
366 orig_ifp = ifp = THREAD_ARG(t);
367 fd = THREAD_FD(t);
368
369 pim_ifp = ifp->info;
370
371 while (cont) {
372 pim_sgaddr sg;
373
374 len = pim_socket_recvfromto(fd, buf, sizeof(buf), &from,
375 &fromlen, &to, &tolen, &ifindex);
376 if (len < 0) {
377 if (errno == EINTR)
378 continue;
379 if (errno == EWOULDBLOCK || errno == EAGAIN)
380 break;
381
382 if (PIM_DEBUG_PIM_PACKETS)
383 zlog_debug("Received errno: %d %s", errno,
384 safe_strerror(errno));
385 goto done;
386 }
387
388 /*
389 * What? So with vrf's the incoming packet is received
390 * on the vrf interface but recvfromto above returns
391 * the right ifindex, so just use it. We know
392 * it's the right interface because we bind to it
393 */
394 ifp = if_lookup_by_index(ifindex, pim_ifp->pim->vrf->vrf_id);
395 if (!ifp || !ifp->info) {
396 if (PIM_DEBUG_PIM_PACKETS)
397 zlog_debug(
398 "%s: Received incoming pim packet on interface(%s:%d) not yet configured for pim",
399 __func__, ifp ? ifp->name : "Unknown",
400 ifindex);
401 goto done;
402 }
403#if PIM_IPV == 4
404 sg.src = ((struct sockaddr_in *)&from)->sin_addr;
405 sg.grp = ((struct sockaddr_in *)&to)->sin_addr;
406#else
407 sg.src = ((struct sockaddr_in6 *)&from)->sin6_addr;
408 sg.grp = ((struct sockaddr_in6 *)&to)->sin6_addr;
409#endif
410
411 int fail = pim_pim_packet(ifp, buf, len, sg);
412 if (fail) {
413 if (PIM_DEBUG_PIM_PACKETS)
414 zlog_debug("%s: pim_pim_packet() return=%d",
415 __func__, fail);
416 goto done;
417 }
418
419 count++;
420 if (count % router->packet_process == 0)
421 cont = 0;
422 }
423
424 result = 0; /* good */
425
426done:
427 pim_sock_read_on(orig_ifp);
428
429 if (result) {
430 ++pim_ifp->pim_ifstat_hello_recvfail;
431 }
432}
433
434static void pim_sock_read_on(struct interface *ifp)
435{
436 struct pim_interface *pim_ifp;
437
438 assert(ifp);
439 assert(ifp->info);
440
441 pim_ifp = ifp->info;
442
443 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
444 zlog_debug("Scheduling READ event on PIM socket fd=%d",
445 pim_ifp->pim_sock_fd);
446 }
447 thread_add_read(router->master, pim_sock_read, ifp,
448 pim_ifp->pim_sock_fd, &pim_ifp->t_pim_sock_read);
449}
450
451static int pim_sock_open(struct interface *ifp)
452{
453 int fd;
454 struct pim_interface *pim_ifp = ifp->info;
455
456 fd = pim_socket_mcast(IPPROTO_PIM, pim_ifp->primary_address, ifp,
457 0 /* loop=false */);
458 if (fd < 0)
459 return -1;
460
461 if (pim_socket_join(fd, qpim_all_pim_routers_addr,
462 pim_ifp->primary_address, ifp->ifindex, pim_ifp)) {
463 close(fd);
464 return -2;
465 }
466
467 return fd;
468}
469
470void pim_ifstat_reset(struct interface *ifp)
471{
472 struct pim_interface *pim_ifp;
473
474 assert(ifp);
475
476 pim_ifp = ifp->info;
477 if (!pim_ifp) {
478 return;
479 }
480
481 pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
482 pim_ifp->pim_ifstat_hello_sent = 0;
483 pim_ifp->pim_ifstat_hello_sendfail = 0;
484 pim_ifp->pim_ifstat_hello_recv = 0;
485 pim_ifp->pim_ifstat_hello_recvfail = 0;
486 pim_ifp->pim_ifstat_bsm_rx = 0;
487 pim_ifp->pim_ifstat_bsm_tx = 0;
488 pim_ifp->pim_ifstat_join_recv = 0;
489 pim_ifp->pim_ifstat_join_send = 0;
490 pim_ifp->pim_ifstat_prune_recv = 0;
491 pim_ifp->pim_ifstat_prune_send = 0;
492 pim_ifp->pim_ifstat_reg_recv = 0;
493 pim_ifp->pim_ifstat_reg_send = 0;
494 pim_ifp->pim_ifstat_reg_stop_recv = 0;
495 pim_ifp->pim_ifstat_reg_stop_send = 0;
496 pim_ifp->pim_ifstat_assert_recv = 0;
497 pim_ifp->pim_ifstat_assert_send = 0;
498 pim_ifp->pim_ifstat_bsm_cfg_miss = 0;
499 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss = 0;
500 pim_ifp->pim_ifstat_bsm_invalid_sz = 0;
501 pim_ifp->igmp_ifstat_joins_sent = 0;
502 pim_ifp->igmp_ifstat_joins_failed = 0;
503 pim_ifp->igmp_peak_group_count = 0;
504}
505
506void pim_sock_reset(struct interface *ifp)
507{
508 struct pim_interface *pim_ifp;
509
510 assert(ifp);
511 assert(ifp->info);
512
513 pim_ifp = ifp->info;
514
515 pim_ifp->primary_address = pim_find_primary_addr(ifp);
516
517 pim_ifp->pim_sock_fd = -1;
518 pim_ifp->pim_sock_creation = 0;
519 pim_ifp->t_pim_sock_read = NULL;
520
521 pim_ifp->t_pim_hello_timer = NULL;
522 pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
523 pim_ifp->pim_default_holdtime =
524 -1; /* unset: means 3.5 * pim_hello_period */
525 pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
526 pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
527 pim_ifp->pim_propagation_delay_msec =
528 PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
529 pim_ifp->pim_override_interval_msec =
530 PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
531 pim_ifp->pim_can_disable_join_suppression =
532 PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION;
533
534 /* neighbors without lan_delay */
535 pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
536 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
537 pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
538
539 /* DR Election */
540 pim_ifp->pim_dr_election_last = 0; /* timestamp */
541 pim_ifp->pim_dr_election_count = 0;
542 pim_ifp->pim_dr_election_changes = 0;
543 pim_ifp->pim_dr_num_nondrpri_neighbors =
544 0; /* neighbors without dr_pri */
545 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
546 pim_ifp->am_i_dr = true;
547
548 pim_ifstat_reset(ifp);
549}
550
551#if PIM_IPV == 4
552static uint16_t ip_id = 0;
553#endif
554
555#if PIM_IPV == 4
556static int pim_msg_send_frame(int fd, char *buf, size_t len,
557 struct sockaddr *dst, size_t salen,
558 const char *ifname)
559{
560 if (sendto(fd, buf, len, MSG_DONTWAIT, dst, salen) >= 0)
561 return 0;
562
563 if (errno == EMSGSIZE) {
564 struct ip *ip = (struct ip *)buf;
565 size_t hdrsize = sizeof(struct ip);
566 size_t newlen1 = ((len - hdrsize) / 2) & 0xFFF8;
567 size_t sendlen = newlen1 + hdrsize;
568 size_t offset = ntohs(ip->ip_off);
569 int ret;
570
571 ip->ip_len = htons(sendlen);
572 ip->ip_off = htons(offset | IP_MF);
573
574 ret = pim_msg_send_frame(fd, buf, sendlen, dst, salen, ifname);
575 if (ret)
576 return ret;
577
578 struct ip *ip2 = (struct ip *)(buf + newlen1);
579 size_t newlen2 = len - sendlen;
580
581 sendlen = newlen2 + hdrsize;
582
583 memcpy(ip2, ip, hdrsize);
584 ip2->ip_len = htons(sendlen);
585 ip2->ip_off = htons(offset + (newlen1 >> 3));
586 return pim_msg_send_frame(fd, (char *)ip2, sendlen, dst, salen,
587 ifname);
588 }
589
590 zlog_warn(
591 "%s: sendto() failure to %pSU: iface=%s fd=%d msg_size=%zd: %m",
592 __func__, dst, ifname, fd, len);
593 return -1;
594}
595
596#else
597static int pim_msg_send_frame(pim_addr src, pim_addr dst, ifindex_t ifindex,
598 struct iovec *message, int fd)
599{
600 int retval;
601 struct msghdr smsghdr = {};
602 struct cmsghdr *scmsgp;
603 union cmsgbuf {
604 struct cmsghdr hdr;
605 uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
606 };
607 struct in6_pktinfo *pktinfo;
608 struct sockaddr_in6 dst_sin6 = {};
609
610 union cmsgbuf cmsg_buf = {};
611
612 /* destination address */
613 dst_sin6.sin6_family = AF_INET6;
614#ifdef SIN6_LEN
615 dst_sin6.sin6_len = sizeof(struct sockaddr_in6);
616#endif /*SIN6_LEN*/
617 dst_sin6.sin6_addr = dst;
618 dst_sin6.sin6_scope_id = ifindex;
619
620 /* send msg hdr */
621 smsghdr.msg_iov = message;
622 smsghdr.msg_iovlen = 1;
623 smsghdr.msg_name = (caddr_t)&dst_sin6;
624 smsghdr.msg_namelen = sizeof(dst_sin6);
625 smsghdr.msg_control = (caddr_t)&cmsg_buf.buf;
626 smsghdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
627 smsghdr.msg_flags = 0;
628
629 scmsgp = CMSG_FIRSTHDR(&smsghdr);
630 scmsgp->cmsg_level = IPPROTO_IPV6;
631 scmsgp->cmsg_type = IPV6_PKTINFO;
632 scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
633
634 pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp));
635 pktinfo->ipi6_ifindex = ifindex;
636 pktinfo->ipi6_addr = src;
637
638 retval = sendmsg(fd, &smsghdr, 0);
639 if (retval < 0)
640 flog_err(
641 EC_LIB_SOCKET,
642 "sendmsg failed: source: %pI6 Dest: %pI6 ifindex: %d: %s (%d)",
643 &src, &dst, ifindex, safe_strerror(errno), errno);
644
645 return retval;
646}
647#endif
648
649int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
650 int pim_msg_size, struct interface *ifp)
651{
652 struct pim_interface *pim_ifp;
653
654
655 pim_ifp = ifp->info;
656
657 if (pim_ifp->pim_passive_enable) {
658 if (PIM_DEBUG_PIM_PACKETS)
659 zlog_debug(
660 "skip sending PIM message on passive interface %s",
661 ifp->name);
662 return 0;
663 }
664
665#if PIM_IPV == 4
666 uint8_t ttl;
667 struct pim_msg_header *header;
668 unsigned char buffer[10000];
669
670 memset(buffer, 0, 10000);
671
672 header = (struct pim_msg_header *)pim_msg;
673
674/*
675 * Omnios apparently doesn't have a #define for IP default
676 * ttl that is the same as all other platforms.
677 */
678#ifndef IPDEFTTL
679#define IPDEFTTL 64
680#endif
681 /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */
682 switch (header->type) {
683 case PIM_MSG_TYPE_HELLO:
684 case PIM_MSG_TYPE_JOIN_PRUNE:
685 case PIM_MSG_TYPE_BOOTSTRAP:
686 case PIM_MSG_TYPE_ASSERT:
687 ttl = 1;
688 break;
689 case PIM_MSG_TYPE_REGISTER:
690 case PIM_MSG_TYPE_REG_STOP:
691 case PIM_MSG_TYPE_GRAFT:
692 case PIM_MSG_TYPE_GRAFT_ACK:
693 case PIM_MSG_TYPE_CANDIDATE:
694 ttl = IPDEFTTL;
695 break;
696 default:
697 ttl = MAXTTL;
698 break;
699 }
700
701 struct ip *ip = (struct ip *)buffer;
702 struct sockaddr_in to = {};
703 int sendlen = sizeof(*ip) + pim_msg_size;
704 socklen_t tolen;
705 unsigned char *msg_start;
706
707 ip->ip_id = htons(++ip_id);
708 ip->ip_hl = 5;
709 ip->ip_v = 4;
710 ip->ip_tos = IPTOS_PREC_INTERNETCONTROL;
711 ip->ip_p = PIM_IP_PROTO_PIM;
712 ip->ip_src = src;
713 ip->ip_dst = dst;
714 ip->ip_ttl = ttl;
715 ip->ip_len = htons(sendlen);
716
717 to.sin_family = AF_INET;
718 to.sin_addr = dst;
719 tolen = sizeof(to);
720
721 msg_start = buffer + sizeof(*ip);
722 memcpy(msg_start, pim_msg, pim_msg_size);
723
724 if (PIM_DEBUG_PIM_PACKETS)
725 zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x",
726 __func__, &dst, ifp->name, pim_msg_size,
727 header->checksum);
728
729 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
730 pim_pkt_dump(__func__, pim_msg, pim_msg_size);
731 }
732
733 pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to,
734 tolen, ifp->name);
735 return 0;
736
737#else
738 struct iovec iovector[2];
739
740 iovector[0].iov_base = pim_msg;
741 iovector[0].iov_len = pim_msg_size;
742
743 pim_msg_send_frame(src, dst, ifp->ifindex, &iovector[0], fd);
744
745 return 0;
746#endif
747}
748
749static int hello_send(struct interface *ifp, uint16_t holdtime)
750{
751 uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
752 struct pim_interface *pim_ifp;
753 int pim_tlv_size;
754 int pim_msg_size;
755
756 pim_ifp = ifp->info;
757
758 if (PIM_DEBUG_PIM_HELLO)
759 zlog_debug(
760 "%s: to %pPA on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d",
761 __func__, &qpim_all_pim_routers_addr, ifp->name,
762 holdtime, pim_ifp->pim_propagation_delay_msec,
763 pim_ifp->pim_override_interval_msec,
764 pim_ifp->pim_can_disable_join_suppression,
765 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
766 listcount(ifp->connected));
767
768 pim_tlv_size = pim_hello_build_tlv(
769 ifp, pim_msg + PIM_PIM_MIN_LEN,
770 sizeof(pim_msg) - PIM_PIM_MIN_LEN, holdtime,
771 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
772 pim_ifp->pim_propagation_delay_msec,
773 pim_ifp->pim_override_interval_msec,
774 pim_ifp->pim_can_disable_join_suppression);
775 if (pim_tlv_size < 0) {
776 return -1;
777 }
778
779 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
780
781 assert(pim_msg_size >= PIM_PIM_MIN_LEN);
782 assert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
783
784 pim_msg_build_header(pim_ifp->primary_address,
785 qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
786 PIM_MSG_TYPE_HELLO, false);
787
788 if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
789 qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
790 ifp)) {
791 if (PIM_DEBUG_PIM_HELLO) {
792 zlog_debug(
793 "%s: could not send PIM message on interface %s",
794 __func__, ifp->name);
795 }
796 return -2;
797 }
798
799 return 0;
800}
801
802int pim_hello_send(struct interface *ifp, uint16_t holdtime)
803{
804 struct pim_interface *pim_ifp = ifp->info;
805
806 if (if_is_loopback(ifp))
807 return 0;
808
809 if (hello_send(ifp, holdtime)) {
810 ++pim_ifp->pim_ifstat_hello_sendfail;
811
812 if (PIM_DEBUG_PIM_HELLO) {
813 zlog_warn("Could not send PIM hello on interface %s",
814 ifp->name);
815 }
816 return -1;
817 }
818
819 if (!pim_ifp->pim_passive_enable) {
820 ++pim_ifp->pim_ifstat_hello_sent;
821 PIM_IF_FLAG_SET_HELLO_SENT(pim_ifp->flags);
822 }
823
824 return 0;
825}
826
827static void hello_resched(struct interface *ifp)
828{
829 struct pim_interface *pim_ifp;
830
831 pim_ifp = ifp->info;
832
833 if (PIM_DEBUG_PIM_HELLO) {
834 zlog_debug("Rescheduling %d sec hello on interface %s",
835 pim_ifp->pim_hello_period, ifp->name);
836 }
837 THREAD_OFF(pim_ifp->t_pim_hello_timer);
838 thread_add_timer(router->master, on_pim_hello_send, ifp,
839 pim_ifp->pim_hello_period,
840 &pim_ifp->t_pim_hello_timer);
841}
842
843/*
844 Periodic hello timer
845 */
846static void on_pim_hello_send(struct thread *t)
847{
848 struct pim_interface *pim_ifp;
849 struct interface *ifp;
850
851 ifp = THREAD_ARG(t);
852 pim_ifp = ifp->info;
853
854 /*
855 * Schedule next hello
856 */
857 hello_resched(ifp);
858
859 /*
860 * Send hello
861 */
862 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
863}
864
865/*
866 RFC 4601: 4.3.1. Sending Hello Messages
867
868 Thus, if a router needs to send a Join/Prune or Assert message on an
869 interface on which it has not yet sent a Hello message with the
870 currently configured IP address, then it MUST immediately send the
871 relevant Hello message without waiting for the Hello Timer to
872 expire, followed by the Join/Prune or Assert message.
873 */
874void pim_hello_restart_now(struct interface *ifp)
875{
876 struct pim_interface *pim_ifp;
877
878 pim_ifp = ifp->info;
879
880 /*
881 * Reset next hello timer
882 */
883 hello_resched(ifp);
884
885 /*
886 * Immediately send hello
887 */
888 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
889}
890
891/*
892 RFC 4601: 4.3.1. Sending Hello Messages
893
894 To allow new or rebooting routers to learn of PIM neighbors quickly,
895 when a Hello message is received from a new neighbor, or a Hello
896 message with a new GenID is received from an existing neighbor, a
897 new Hello message should be sent on this interface after a
898 randomized delay between 0 and Triggered_Hello_Delay.
899 */
900void pim_hello_restart_triggered(struct interface *ifp)
901{
902 struct pim_interface *pim_ifp;
903 int triggered_hello_delay_msec;
904 int random_msec;
905
906 pim_ifp = ifp->info;
907
908 /*
909 * No need to ever start loopback or vrf device hello's
910 */
911 if (if_is_loopback(ifp))
912 return;
913
914 /*
915 * There exists situations where we have the a RPF out this
916 * interface, but we haven't formed a neighbor yet. This
917 * happens especially during interface flaps. While
918 * we would like to handle this more gracefully in other
919 * parts of the code. In order to get us up and running
920 * let's just send the hello immediate'ish
921 * This should be revisited when we get nexthop tracking
922 * in and when we have a better handle on safely
923 * handling the rpf information for upstreams that
924 * we cannot legally reach yet.
925 */
926 triggered_hello_delay_msec = 1;
927 // triggered_hello_delay_msec = 1000 *
928 // pim_ifp->pim_triggered_hello_delay;
929
930 if (pim_ifp->t_pim_hello_timer) {
931 long remain_msec =
932 pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
933 if (remain_msec <= triggered_hello_delay_msec) {
934 /* Rescheduling hello would increase the delay, then
935 it's faster
936 to just wait for the scheduled periodic hello. */
937 return;
938 }
939
940 THREAD_OFF(pim_ifp->t_pim_hello_timer);
941 }
942
943 random_msec = triggered_hello_delay_msec;
944 // random_msec = random() % (triggered_hello_delay_msec + 1);
945
946 if (PIM_DEBUG_PIM_HELLO) {
947 zlog_debug("Scheduling %d msec triggered hello on interface %s",
948 random_msec, ifp->name);
949 }
950
951 thread_add_timer_msec(router->master, on_pim_hello_send, ifp,
952 random_msec, &pim_ifp->t_pim_hello_timer);
953}
954
955int pim_sock_add(struct interface *ifp)
956{
957 struct pim_interface *pim_ifp;
958 uint32_t old_genid;
959
960 pim_ifp = ifp->info;
961 assert(pim_ifp);
962
963 if (pim_ifp->pim_sock_fd >= 0) {
964 if (PIM_DEBUG_PIM_PACKETS)
965 zlog_debug(
966 "Can't recreate existing PIM socket fd=%d for interface %s",
967 pim_ifp->pim_sock_fd, ifp->name);
968 return -1;
969 }
970
971 pim_ifp->pim_sock_fd = pim_sock_open(ifp);
972 if (pim_ifp->pim_sock_fd < 0) {
973 if (PIM_DEBUG_PIM_PACKETS)
974 zlog_debug("Could not open PIM socket on interface %s",
975 ifp->name);
976 return -2;
977 }
978
979 pim_socket_ip_hdr(pim_ifp->pim_sock_fd);
980
981 pim_ifp->t_pim_sock_read = NULL;
982 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
983
984 /*
985 * Just ensure that the new generation id
986 * actually chooses something different.
987 * Actually ran across a case where this
988 * happened, pre-switch to random().
989 * While this is unlikely to happen now
990 * let's make sure it doesn't.
991 */
992 old_genid = pim_ifp->pim_generation_id;
993
994 while (old_genid == pim_ifp->pim_generation_id)
995 pim_ifp->pim_generation_id = frr_weak_random();
996
997 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp->name,
998 ifp->ifindex);
999
1000 /*
1001 * Start receiving PIM messages
1002 */
1003 pim_sock_read_on(ifp);
1004
1005 /*
1006 * Start sending PIM hello's
1007 */
1008 pim_hello_restart_triggered(ifp);
1009
1010 return 0;
1011}