]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_pim.c
*: Convert THREAD_XXX macros to EVENT_XXX macros
[mirror_frr.git] / pimd / pim_pim.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
12e41d03 2/*
896014f4
DL
3 * PIM for Quagga
4 * Copyright (C) 2008 Everton da Silva Marques
896014f4 5 */
12e41d03
DL
6
7#include <zebra.h>
8
9#include "log.h"
cb37cb33 10#include "event.h"
12e41d03 11#include "memory.h"
744d91b3 12#include "if.h"
5920b3eb 13#include "network.h"
12e41d03
DL
14
15#include "pimd.h"
993e3d8e 16#include "pim_instance.h"
12e41d03
DL
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"
77e390e5 29#include "pim_register.h"
d9ff4302 30#include "pim_errors.h"
d57a8bbf 31#include "pim_bsm.h"
529f5225 32#include <lib/lib_errors.h>
12e41d03 33
e6685141 34static void on_pim_hello_send(struct event *t);
12e41d03 35
d62a17ae 36static const char *pim_pim_msgtype2str(enum pim_msg_type type)
7643f0a1 37{
d62a17ae 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";
7643f0a1
DS
60}
61
12e41d03
DL
62static void sock_close(struct interface *ifp)
63{
d62a17ae 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 }
e16d030c 73 EVENT_OFF(pim_ifp->t_pim_sock_read);
d62a17ae 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 }
e16d030c 82 EVENT_OFF(pim_ifp->t_pim_hello_timer);
d62a17ae 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;
12e41d03
DL
101}
102
103void pim_sock_delete(struct interface *ifp, const char *delete_message)
104{
d62a17ae 105 zlog_info("PIM INTERFACE DOWN: on interface %s: %s", ifp->name,
106 delete_message);
107
108 if (!ifp->info) {
298004a1 109 flog_err(EC_PIM_CONFIG,
1c50c1c0 110 "%s: %s: but PIM not enabled on interface %s (!)",
15569c58 111 __func__, delete_message, ifp->name);
d62a17ae 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);
12e41d03
DL
127}
128
23a2f90a 129/* For now check dst address for hello, assrt and join/prune is all pim rtr */
f20d0d7c 130static bool pim_pkt_dst_addr_ok(enum pim_msg_type type, pim_addr addr)
23a2f90a 131{
132 if ((type == PIM_MSG_TYPE_HELLO) || (type == PIM_MSG_TYPE_ASSERT)
133 || (type == PIM_MSG_TYPE_JOIN_PRUNE)) {
f20d0d7c 134 if (pim_addr_cmp(addr, qpim_all_pim_routers_addr))
23a2f90a 135 return false;
136 }
137
138 return true;
139}
140
5e6e8a39
DL
141int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
142 pim_sgaddr sg)
12e41d03 143{
721c7be3 144 struct iovec iov[2], *iovp = iov;
5e6e8a39 145#if PIM_IPV == 4
5e2b2033 146 struct ip *ip_hdr = (struct ip *)buf;
d62a17ae 147 size_t ip_hlen; /* ip header length in bytes */
5e6e8a39 148#endif
d62a17ae 149 uint8_t *pim_msg;
5e2b2033 150 uint32_t pim_msg_len = 0;
d62a17ae 151 uint16_t pim_checksum; /* received checksum */
152 uint16_t checksum; /* computed checksum */
153 struct pim_neighbor *neigh;
154 struct pim_msg_header *header;
5acde1cf 155 bool no_fwd;
d62a17ae 156
5e6e8a39 157#if PIM_IPV == 4
d62a17ae 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
d62a17ae 166 ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
5e6e8a39 167 sg = pim_sgaddr_from_iphdr(ip_hdr);
d62a17ae 168
169 pim_msg = buf + ip_hlen;
170 pim_msg_len = len - ip_hlen;
5e6e8a39 171#else
721c7be3
DL
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
5e6e8a39
DL
183 /* NB: header is not included in IPv6 RX */
184 pim_msg = buf;
185 pim_msg_len = len;
186#endif
d62a17ae 187
721c7be3
DL
188 iovp->iov_base = pim_msg;
189 iovp->iov_len = pim_msg_len;
190 iovp++;
191
d62a17ae 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;
5acde1cf 214 no_fwd = header->Nbit;
d62a17ae 215
216 if (header->type == PIM_MSG_TYPE_REGISTER) {
06424db4
DS
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 }
721c7be3
DL
223
224#if PIM_IPV == 6
225 phdr.ulpl = htonl(PIM_MSG_REGISTER_LEN);
226#endif
d62a17ae 227 /* First 8 byte header checksum */
721c7be3
DL
228 iovp[-1].iov_len = PIM_MSG_REGISTER_LEN;
229 checksum = in_cksumv(iov, iovp - iov);
230
d62a17ae 231 if (checksum != pim_checksum) {
721c7be3
DL
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);
d62a17ae 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 {
721c7be3 249 checksum = in_cksumv(iov, iovp - iov);
d62a17ae 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) {
d62a17ae 261 zlog_debug(
5e2b2033
MR
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)
15569c58 266 pim_pkt_dump(__func__, pim_msg, pim_msg_len);
d62a17ae 267 }
268
5e2b2033 269 if (!pim_pkt_dst_addr_ok(header->type, sg.grp)) {
23a2f90a 270 zlog_warn(
5e2b2033
MR
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);
23a2f90a 274 return -1;
275 }
276
d62a17ae 277 switch (header->type) {
278 case PIM_MSG_TYPE_HELLO:
5e2b2033 279 return pim_hello_recv(ifp, sg.src, pim_msg + PIM_MSG_HEADER_LEN,
d62a17ae 280 pim_msg_len - PIM_MSG_HEADER_LEN);
281 break;
282 case PIM_MSG_TYPE_REGISTER:
5e2b2033 283 return pim_register_recv(ifp, sg.grp, sg.src,
d62a17ae 284 pim_msg + PIM_MSG_HEADER_LEN,
285 pim_msg_len - PIM_MSG_HEADER_LEN);
286 break;
287 case PIM_MSG_TYPE_REG_STOP:
b206566b 288 return pim_register_stop_recv(ifp, pim_msg + PIM_MSG_HEADER_LEN,
d62a17ae 289 pim_msg_len - PIM_MSG_HEADER_LEN);
290 break;
291 case PIM_MSG_TYPE_JOIN_PRUNE:
3dbf370a 292 neigh = pim_neighbor_find(ifp, sg.src, false);
d62a17ae 293 if (!neigh) {
294 if (PIM_DEBUG_PIM_PACKETS)
295 zlog_debug(
5e2b2033 296 "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
15569c58 297 __FILE__, __func__, header->type,
5e2b2033 298 &sg.src, ifp->name);
d62a17ae 299 return -1;
300 }
301 pim_neighbor_timer_reset(neigh, neigh->holdtime);
5e2b2033 302 return pim_joinprune_recv(ifp, neigh, sg.src,
d62a17ae 303 pim_msg + PIM_MSG_HEADER_LEN,
304 pim_msg_len - PIM_MSG_HEADER_LEN);
305 break;
306 case PIM_MSG_TYPE_ASSERT:
3dbf370a 307 neigh = pim_neighbor_find(ifp, sg.src, false);
d62a17ae 308 if (!neigh) {
309 if (PIM_DEBUG_PIM_PACKETS)
310 zlog_debug(
5e2b2033 311 "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
15569c58 312 __FILE__, __func__, header->type,
5e2b2033 313 &sg.src, ifp->name);
d62a17ae 314 return -1;
315 }
316 pim_neighbor_timer_reset(neigh, neigh->holdtime);
5e2b2033 317 return pim_assert_recv(ifp, neigh, sg.src,
d62a17ae 318 pim_msg + PIM_MSG_HEADER_LEN,
319 pim_msg_len - PIM_MSG_HEADER_LEN);
320 break;
5acde1cf 321 case PIM_MSG_TYPE_BOOTSTRAP:
5e2b2033 322 return pim_bsm_process(ifp, &sg, pim_msg, pim_msg_len, no_fwd);
5acde1cf 323 break;
d57a8bbf 324
d62a17ae 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 }
12e41d03
DL
333}
334
335static void pim_sock_read_on(struct interface *ifp);
336
e6685141 337static void pim_sock_read(struct event *t)
12e41d03 338{
9487552c 339 struct interface *ifp, *orig_ifp;
d62a17ae 340 struct pim_interface *pim_ifp;
341 int fd;
023d3e4a
BG
342 struct sockaddr_storage from;
343 struct sockaddr_storage to;
d62a17ae 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
e16d030c
DS
353 orig_ifp = ifp = EVENT_ARG(t);
354 fd = EVENT_FD(t);
d62a17ae 355
356 pim_ifp = ifp->info;
357
358 while (cont) {
5e6e8a39
DL
359 pim_sgaddr sg;
360
d62a17ae 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 }
12e41d03 374
e2d451e2
DS
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 */
d3cc1e45 381 ifp = if_lookup_by_index(ifindex, pim_ifp->pim->vrf->vrf_id);
05d8470f 382 if (!ifp || !ifp->info) {
a5b6bd2b
DS
383 if (PIM_DEBUG_PIM_PACKETS)
384 zlog_debug(
8cd38306 385 "%s: Received incoming pim packet on interface(%s:%d) not yet configured for pim",
15569c58
DA
386 __func__, ifp ? ifp->name : "Unknown",
387 ifindex);
a5b6bd2b
DS
388 goto done;
389 }
5e6e8a39
DL
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);
d62a17ae 399 if (fail) {
400 if (PIM_DEBUG_PIM_PACKETS)
401 zlog_debug("%s: pim_pim_packet() return=%d",
15569c58 402 __func__, fail);
d62a17ae 403 goto done;
404 }
405
406 count++;
75373cca 407 if (count % router->packet_process == 0)
d62a17ae 408 cont = 0;
409 }
12e41d03 410
d62a17ae 411 result = 0; /* good */
12e41d03 412
d62a17ae 413done:
9487552c 414 pim_sock_read_on(orig_ifp);
12e41d03 415
d62a17ae 416 if (result) {
417 ++pim_ifp->pim_ifstat_hello_recvfail;
418 }
12e41d03
DL
419}
420
421static void pim_sock_read_on(struct interface *ifp)
422{
d62a17ae 423 struct pim_interface *pim_ifp;
12e41d03 424
df5dfb77
DL
425 assert(ifp);
426 assert(ifp->info);
12e41d03 427
d62a17ae 428 pim_ifp = ifp->info;
12e41d03 429
d62a17ae 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 }
907a2395
DS
434 event_add_read(router->master, pim_sock_read, ifp, pim_ifp->pim_sock_fd,
435 &pim_ifp->t_pim_sock_read);
12e41d03
DL
436}
437
e5dfe687 438static int pim_sock_open(struct interface *ifp)
12e41d03 439{
d62a17ae 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,
f2058cb4 449 pim_ifp->primary_address, ifp->ifindex, pim_ifp)) {
d62a17ae 450 close(fd);
451 return -2;
452 }
12e41d03 453
d62a17ae 454 return fd;
12e41d03
DL
455}
456
457void pim_ifstat_reset(struct interface *ifp)
458{
d62a17ae 459 struct pim_interface *pim_ifp;
12e41d03 460
df5dfb77 461 assert(ifp);
12e41d03 462
d62a17ae 463 pim_ifp = ifp->info;
464 if (!pim_ifp) {
465 return;
466 }
12e41d03 467
d62a17ae 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;
79992e8a
MR
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;
f2058cb4
DA
488 pim_ifp->igmp_ifstat_joins_sent = 0;
489 pim_ifp->igmp_ifstat_joins_failed = 0;
3e5d8665 490 pim_ifp->igmp_peak_group_count = 0;
12e41d03
DL
491}
492
493void pim_sock_reset(struct interface *ifp)
494{
d62a17ae 495 struct pim_interface *pim_ifp;
496
df5dfb77
DL
497 assert(ifp);
498 assert(ifp->info);
d62a17ae 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;
b6fcc0b7
DL
518 pim_ifp->pim_can_disable_join_suppression =
519 PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION;
d62a17ae 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;
46a9ea8b 533 pim_ifp->am_i_dr = true;
d62a17ae 534
535 pim_ifstat_reset(ifp);
12e41d03
DL
536}
537
cc362d24 538#if PIM_IPV == 4
4df01a4e 539static uint16_t ip_id = 0;
cc362d24 540#endif
c305ed63 541
529f5225 542#if PIM_IPV == 4
d62a17ae 543static int pim_msg_send_frame(int fd, char *buf, size_t len,
516b97fe
DL
544 struct sockaddr *dst, size_t salen,
545 const char *ifname)
c305ed63 546{
e7485deb
DL
547 if (sendto(fd, buf, len, MSG_DONTWAIT, dst, salen) >= 0)
548 return 0;
d62a17ae 549
e7485deb
DL
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);
c305ed63 575 }
c305ed63 576
e7485deb
DL
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;
c305ed63
DS
581}
582
529f5225
BG
583#else
584static 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
29fd9fca 636int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
03c106bf 637 int pim_msg_size, struct interface *ifp)
12e41d03 638{
03c106bf 639 struct pim_interface *pim_ifp;
640
529f5225 641
03c106bf 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 }
d62a17ae 651
529f5225
BG
652#if PIM_IPV == 4
653 uint8_t ttl;
654 struct pim_msg_header *header;
655 unsigned char buffer[10000];
656
d62a17ae 657 memset(buffer, 0, 10000);
d62a17ae 658
659 header = (struct pim_msg_header *)pim_msg;
529f5225 660
d62a17ae 661/*
662 * Omnios apparently doesn't have a #define for IP default
663 * ttl that is the same as all other platforms.
664 */
05ea5cee
DS
665#ifndef IPDEFTTL
666#define IPDEFTTL 64
667#endif
d62a17ae 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
cc362d24
DL
688 struct ip *ip = (struct ip *)buffer;
689 struct sockaddr_in to = {};
690 int sendlen = sizeof(*ip) + pim_msg_size;
529f5225
BG
691 socklen_t tolen;
692 unsigned char *msg_start;
cc362d24 693
d62a17ae 694 ip->ip_id = htons(++ip_id);
695 ip->ip_hl = 5;
696 ip->ip_v = 4;
9036d0ef 697 ip->ip_tos = IPTOS_PREC_INTERNETCONTROL;
d62a17ae 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
d62a17ae 704 to.sin_family = AF_INET;
705 to.sin_addr = dst;
706 tolen = sizeof(to);
cc362d24
DL
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",
03c106bf 713 __func__, &dst, ifp->name, pim_msg_size,
cc362d24 714 header->checksum);
d62a17ae 715
716 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
15569c58 717 pim_pkt_dump(__func__, pim_msg, pim_msg_size);
d62a17ae 718 }
719
720 pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to,
03c106bf 721 tolen, ifp->name);
d62a17ae 722 return 0;
529f5225
BG
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
12e41d03
DL
734}
735
d62a17ae 736static int hello_send(struct interface *ifp, uint16_t holdtime)
12e41d03 737{
d62a17ae 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
cc362d24 745 if (PIM_DEBUG_PIM_HELLO)
d62a17ae 746 zlog_debug(
cc362d24
DL
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,
d62a17ae 750 pim_ifp->pim_override_interval_msec,
b6fcc0b7 751 pim_ifp->pim_can_disable_join_suppression,
d62a17ae 752 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
753 listcount(ifp->connected));
d62a17ae 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,
b6fcc0b7 761 pim_ifp->pim_can_disable_join_suppression);
d62a17ae 762 if (pim_tlv_size < 0) {
763 return -1;
764 }
765
766 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
767
df5dfb77
DL
768 assert(pim_msg_size >= PIM_PIM_MIN_LEN);
769 assert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
d62a17ae 770
145e4c38
DL
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);
d62a17ae 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,
11e771be 777 ifp)) {
d62a17ae 778 if (PIM_DEBUG_PIM_HELLO) {
779 zlog_debug(
780 "%s: could not send PIM message on interface %s",
15569c58 781 __func__, ifp->name);
d62a17ae 782 }
783 return -2;
784 }
785
786 return 0;
12e41d03
DL
787}
788
b279f95c 789int pim_hello_send(struct interface *ifp, uint16_t holdtime)
12e41d03 790{
11699c47 791 struct pim_interface *pim_ifp = ifp->info;
12e41d03 792
608c8870 793 if (if_is_loopback(ifp))
d62a17ae 794 return 0;
85b62aea 795
d62a17ae 796 if (hello_send(ifp, holdtime)) {
797 ++pim_ifp->pim_ifstat_hello_sendfail;
12e41d03 798
d62a17ae 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 }
12e41d03 805
11e771be 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 }
12e41d03 810
d62a17ae 811 return 0;
12e41d03
DL
812}
813
814static void hello_resched(struct interface *ifp)
815{
d62a17ae 816 struct pim_interface *pim_ifp;
817
d62a17ae 818 pim_ifp = ifp->info;
d62a17ae 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 }
e16d030c 824 EVENT_OFF(pim_ifp->t_pim_hello_timer);
907a2395
DS
825 event_add_timer(router->master, on_pim_hello_send, ifp,
826 pim_ifp->pim_hello_period, &pim_ifp->t_pim_hello_timer);
12e41d03
DL
827}
828
829/*
830 Periodic hello timer
831 */
e6685141 832static void on_pim_hello_send(struct event *t)
12e41d03 833{
d62a17ae 834 struct pim_interface *pim_ifp;
835 struct interface *ifp;
12e41d03 836
e16d030c 837 ifp = EVENT_ARG(t);
d62a17ae 838 pim_ifp = ifp->info;
12e41d03 839
d62a17ae 840 /*
841 * Schedule next hello
842 */
843 hello_resched(ifp);
12e41d03 844
d62a17ae 845 /*
846 * Send hello
847 */
cc9f21da 848 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
12e41d03
DL
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 */
860void pim_hello_restart_now(struct interface *ifp)
861{
d62a17ae 862 struct pim_interface *pim_ifp;
12e41d03 863
d62a17ae 864 pim_ifp = ifp->info;
12e41d03 865
d62a17ae 866 /*
867 * Reset next hello timer
868 */
869 hello_resched(ifp);
12e41d03 870
d62a17ae 871 /*
872 * Immediately send hello
873 */
874 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
12e41d03
DL
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 */
886void pim_hello_restart_triggered(struct interface *ifp)
887{
d62a17ae 888 struct pim_interface *pim_ifp;
889 int triggered_hello_delay_msec;
890 int random_msec;
891
d62a17ae 892 pim_ifp = ifp->info;
2aa1ca84
DS
893
894 /*
895 * No need to ever start loopback or vrf device hello's
896 */
608c8870 897 if (if_is_loopback(ifp))
2aa1ca84 898 return;
d62a17ae 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
e16d030c 926 EVENT_OFF(pim_ifp->t_pim_hello_timer);
d62a17ae 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
907a2395
DS
937 event_add_timer_msec(router->master, on_pim_hello_send, ifp,
938 random_msec, &pim_ifp->t_pim_hello_timer);
12e41d03
DL
939}
940
941int pim_sock_add(struct interface *ifp)
942{
d62a17ae 943 struct pim_interface *pim_ifp;
944 uint32_t old_genid;
945
946 pim_ifp = ifp->info;
df5dfb77 947 assert(pim_ifp);
d62a17ae 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)
5920b3eb 981 pim_ifp->pim_generation_id = frr_weak_random();
d62a17ae 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;
12e41d03 997}