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