]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_pim.c
bgpd: fix the IGP metric for best path selection on VPN import
[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"
5920b3eb 26#include "network.h"
12e41d03
DL
27
28#include "pimd.h"
993e3d8e 29#include "pim_instance.h"
12e41d03
DL
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"
77e390e5 42#include "pim_register.h"
d9ff4302 43#include "pim_errors.h"
d57a8bbf 44#include "pim_bsm.h"
529f5225 45#include <lib/lib_errors.h>
12e41d03 46
cc9f21da 47static void on_pim_hello_send(struct thread *t);
12e41d03 48
d62a17ae 49static const char *pim_pim_msgtype2str(enum pim_msg_type type)
7643f0a1 50{
d62a17ae 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";
7643f0a1
DS
73}
74
12e41d03
DL
75static void sock_close(struct interface *ifp)
76{
d62a17ae 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;
12e41d03
DL
114}
115
116void pim_sock_delete(struct interface *ifp, const char *delete_message)
117{
d62a17ae 118 zlog_info("PIM INTERFACE DOWN: on interface %s: %s", ifp->name,
119 delete_message);
120
121 if (!ifp->info) {
298004a1 122 flog_err(EC_PIM_CONFIG,
1c50c1c0 123 "%s: %s: but PIM not enabled on interface %s (!)",
15569c58 124 __func__, delete_message, ifp->name);
d62a17ae 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);
12e41d03
DL
140}
141
23a2f90a 142/* For now check dst address for hello, assrt and join/prune is all pim rtr */
f20d0d7c 143static bool pim_pkt_dst_addr_ok(enum pim_msg_type type, pim_addr addr)
23a2f90a 144{
145 if ((type == PIM_MSG_TYPE_HELLO) || (type == PIM_MSG_TYPE_ASSERT)
146 || (type == PIM_MSG_TYPE_JOIN_PRUNE)) {
f20d0d7c 147 if (pim_addr_cmp(addr, qpim_all_pim_routers_addr))
23a2f90a 148 return false;
149 }
150
151 return true;
152}
153
5e6e8a39
DL
154int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
155 pim_sgaddr sg)
12e41d03 156{
721c7be3 157 struct iovec iov[2], *iovp = iov;
5e6e8a39 158#if PIM_IPV == 4
5e2b2033 159 struct ip *ip_hdr = (struct ip *)buf;
d62a17ae 160 size_t ip_hlen; /* ip header length in bytes */
5e6e8a39 161#endif
d62a17ae 162 uint8_t *pim_msg;
5e2b2033 163 uint32_t pim_msg_len = 0;
d62a17ae 164 uint16_t pim_checksum; /* received checksum */
165 uint16_t checksum; /* computed checksum */
166 struct pim_neighbor *neigh;
167 struct pim_msg_header *header;
5acde1cf 168 bool no_fwd;
d62a17ae 169
5e6e8a39 170#if PIM_IPV == 4
d62a17ae 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
d62a17ae 179 ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
5e6e8a39 180 sg = pim_sgaddr_from_iphdr(ip_hdr);
d62a17ae 181
182 pim_msg = buf + ip_hlen;
183 pim_msg_len = len - ip_hlen;
5e6e8a39 184#else
721c7be3
DL
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
5e6e8a39
DL
196 /* NB: header is not included in IPv6 RX */
197 pim_msg = buf;
198 pim_msg_len = len;
199#endif
d62a17ae 200
721c7be3
DL
201 iovp->iov_base = pim_msg;
202 iovp->iov_len = pim_msg_len;
203 iovp++;
204
d62a17ae 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;
5acde1cf 227 no_fwd = header->Nbit;
d62a17ae 228
229 if (header->type == PIM_MSG_TYPE_REGISTER) {
06424db4
DS
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 }
721c7be3
DL
236
237#if PIM_IPV == 6
238 phdr.ulpl = htonl(PIM_MSG_REGISTER_LEN);
239#endif
d62a17ae 240 /* First 8 byte header checksum */
721c7be3
DL
241 iovp[-1].iov_len = PIM_MSG_REGISTER_LEN;
242 checksum = in_cksumv(iov, iovp - iov);
243
d62a17ae 244 if (checksum != pim_checksum) {
721c7be3
DL
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);
d62a17ae 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 {
721c7be3 262 checksum = in_cksumv(iov, iovp - iov);
d62a17ae 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) {
d62a17ae 274 zlog_debug(
5e2b2033
MR
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)
15569c58 279 pim_pkt_dump(__func__, pim_msg, pim_msg_len);
d62a17ae 280 }
281
5e2b2033 282 if (!pim_pkt_dst_addr_ok(header->type, sg.grp)) {
23a2f90a 283 zlog_warn(
5e2b2033
MR
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);
23a2f90a 287 return -1;
288 }
289
d62a17ae 290 switch (header->type) {
291 case PIM_MSG_TYPE_HELLO:
5e2b2033 292 return pim_hello_recv(ifp, sg.src, pim_msg + PIM_MSG_HEADER_LEN,
d62a17ae 293 pim_msg_len - PIM_MSG_HEADER_LEN);
294 break;
295 case PIM_MSG_TYPE_REGISTER:
5e2b2033 296 return pim_register_recv(ifp, sg.grp, sg.src,
d62a17ae 297 pim_msg + PIM_MSG_HEADER_LEN,
298 pim_msg_len - PIM_MSG_HEADER_LEN);
299 break;
300 case PIM_MSG_TYPE_REG_STOP:
b206566b 301 return pim_register_stop_recv(ifp, pim_msg + PIM_MSG_HEADER_LEN,
d62a17ae 302 pim_msg_len - PIM_MSG_HEADER_LEN);
303 break;
304 case PIM_MSG_TYPE_JOIN_PRUNE:
5e2b2033 305 neigh = pim_neighbor_find(ifp, sg.src);
d62a17ae 306 if (!neigh) {
307 if (PIM_DEBUG_PIM_PACKETS)
308 zlog_debug(
5e2b2033 309 "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
15569c58 310 __FILE__, __func__, header->type,
5e2b2033 311 &sg.src, ifp->name);
d62a17ae 312 return -1;
313 }
314 pim_neighbor_timer_reset(neigh, neigh->holdtime);
5e2b2033 315 return pim_joinprune_recv(ifp, neigh, sg.src,
d62a17ae 316 pim_msg + PIM_MSG_HEADER_LEN,
317 pim_msg_len - PIM_MSG_HEADER_LEN);
318 break;
319 case PIM_MSG_TYPE_ASSERT:
5e2b2033 320 neigh = pim_neighbor_find(ifp, sg.src);
d62a17ae 321 if (!neigh) {
322 if (PIM_DEBUG_PIM_PACKETS)
323 zlog_debug(
5e2b2033 324 "%s %s: non-hello PIM message type=%d from non-neighbor %pPA on %s",
15569c58 325 __FILE__, __func__, header->type,
5e2b2033 326 &sg.src, ifp->name);
d62a17ae 327 return -1;
328 }
329 pim_neighbor_timer_reset(neigh, neigh->holdtime);
5e2b2033 330 return pim_assert_recv(ifp, neigh, sg.src,
d62a17ae 331 pim_msg + PIM_MSG_HEADER_LEN,
332 pim_msg_len - PIM_MSG_HEADER_LEN);
333 break;
5acde1cf 334 case PIM_MSG_TYPE_BOOTSTRAP:
5e2b2033 335 return pim_bsm_process(ifp, &sg, pim_msg, pim_msg_len, no_fwd);
5acde1cf 336 break;
d57a8bbf 337
d62a17ae 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 }
12e41d03
DL
346}
347
348static void pim_sock_read_on(struct interface *ifp);
349
cc9f21da 350static void pim_sock_read(struct thread *t)
12e41d03 351{
9487552c 352 struct interface *ifp, *orig_ifp;
d62a17ae 353 struct pim_interface *pim_ifp;
354 int fd;
023d3e4a
BG
355 struct sockaddr_storage from;
356 struct sockaddr_storage to;
d62a17ae 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
9487552c 366 orig_ifp = ifp = THREAD_ARG(t);
d62a17ae 367 fd = THREAD_FD(t);
368
369 pim_ifp = ifp->info;
370
371 while (cont) {
5e6e8a39
DL
372 pim_sgaddr sg;
373
d62a17ae 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 }
12e41d03 387
e2d451e2
DS
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 */
d3cc1e45 394 ifp = if_lookup_by_index(ifindex, pim_ifp->pim->vrf->vrf_id);
05d8470f 395 if (!ifp || !ifp->info) {
a5b6bd2b
DS
396 if (PIM_DEBUG_PIM_PACKETS)
397 zlog_debug(
8cd38306 398 "%s: Received incoming pim packet on interface(%s:%d) not yet configured for pim",
15569c58
DA
399 __func__, ifp ? ifp->name : "Unknown",
400 ifindex);
a5b6bd2b
DS
401 goto done;
402 }
5e6e8a39
DL
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);
d62a17ae 412 if (fail) {
413 if (PIM_DEBUG_PIM_PACKETS)
414 zlog_debug("%s: pim_pim_packet() return=%d",
15569c58 415 __func__, fail);
d62a17ae 416 goto done;
417 }
418
419 count++;
75373cca 420 if (count % router->packet_process == 0)
d62a17ae 421 cont = 0;
422 }
12e41d03 423
d62a17ae 424 result = 0; /* good */
12e41d03 425
d62a17ae 426done:
9487552c 427 pim_sock_read_on(orig_ifp);
12e41d03 428
d62a17ae 429 if (result) {
430 ++pim_ifp->pim_ifstat_hello_recvfail;
431 }
12e41d03
DL
432}
433
434static void pim_sock_read_on(struct interface *ifp)
435{
d62a17ae 436 struct pim_interface *pim_ifp;
12e41d03 437
df5dfb77
DL
438 assert(ifp);
439 assert(ifp->info);
12e41d03 440
d62a17ae 441 pim_ifp = ifp->info;
12e41d03 442
d62a17ae 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 }
36417fcc
DS
447 thread_add_read(router->master, pim_sock_read, ifp,
448 pim_ifp->pim_sock_fd, &pim_ifp->t_pim_sock_read);
12e41d03
DL
449}
450
e5dfe687 451static int pim_sock_open(struct interface *ifp)
12e41d03 452{
d62a17ae 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,
f2058cb4 462 pim_ifp->primary_address, ifp->ifindex, pim_ifp)) {
d62a17ae 463 close(fd);
464 return -2;
465 }
12e41d03 466
d62a17ae 467 return fd;
12e41d03
DL
468}
469
470void pim_ifstat_reset(struct interface *ifp)
471{
d62a17ae 472 struct pim_interface *pim_ifp;
12e41d03 473
df5dfb77 474 assert(ifp);
12e41d03 475
d62a17ae 476 pim_ifp = ifp->info;
477 if (!pim_ifp) {
478 return;
479 }
12e41d03 480
d62a17ae 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;
79992e8a
MR
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;
f2058cb4
DA
501 pim_ifp->igmp_ifstat_joins_sent = 0;
502 pim_ifp->igmp_ifstat_joins_failed = 0;
3e5d8665 503 pim_ifp->igmp_peak_group_count = 0;
12e41d03
DL
504}
505
506void pim_sock_reset(struct interface *ifp)
507{
d62a17ae 508 struct pim_interface *pim_ifp;
509
df5dfb77
DL
510 assert(ifp);
511 assert(ifp->info);
d62a17ae 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;
b6fcc0b7
DL
531 pim_ifp->pim_can_disable_join_suppression =
532 PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION;
d62a17ae 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;
46a9ea8b 546 pim_ifp->am_i_dr = true;
d62a17ae 547
548 pim_ifstat_reset(ifp);
12e41d03
DL
549}
550
cc362d24 551#if PIM_IPV == 4
4df01a4e 552static uint16_t ip_id = 0;
cc362d24 553#endif
c305ed63 554
529f5225 555#if PIM_IPV == 4
d62a17ae 556static int pim_msg_send_frame(int fd, char *buf, size_t len,
516b97fe
DL
557 struct sockaddr *dst, size_t salen,
558 const char *ifname)
c305ed63 559{
e7485deb
DL
560 if (sendto(fd, buf, len, MSG_DONTWAIT, dst, salen) >= 0)
561 return 0;
d62a17ae 562
e7485deb
DL
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);
c305ed63 588 }
c305ed63 589
e7485deb
DL
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;
c305ed63
DS
594}
595
529f5225
BG
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
29fd9fca 649int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
03c106bf 650 int pim_msg_size, struct interface *ifp)
12e41d03 651{
03c106bf 652 struct pim_interface *pim_ifp;
653
529f5225 654
03c106bf 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 }
d62a17ae 664
529f5225
BG
665#if PIM_IPV == 4
666 uint8_t ttl;
667 struct pim_msg_header *header;
668 unsigned char buffer[10000];
669
d62a17ae 670 memset(buffer, 0, 10000);
d62a17ae 671
672 header = (struct pim_msg_header *)pim_msg;
529f5225 673
d62a17ae 674/*
675 * Omnios apparently doesn't have a #define for IP default
676 * ttl that is the same as all other platforms.
677 */
05ea5cee
DS
678#ifndef IPDEFTTL
679#define IPDEFTTL 64
680#endif
d62a17ae 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
cc362d24
DL
701 struct ip *ip = (struct ip *)buffer;
702 struct sockaddr_in to = {};
703 int sendlen = sizeof(*ip) + pim_msg_size;
529f5225
BG
704 socklen_t tolen;
705 unsigned char *msg_start;
cc362d24 706
d62a17ae 707 ip->ip_id = htons(++ip_id);
708 ip->ip_hl = 5;
709 ip->ip_v = 4;
9036d0ef 710 ip->ip_tos = IPTOS_PREC_INTERNETCONTROL;
d62a17ae 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
d62a17ae 717 to.sin_family = AF_INET;
718 to.sin_addr = dst;
719 tolen = sizeof(to);
cc362d24
DL
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",
03c106bf 726 __func__, &dst, ifp->name, pim_msg_size,
cc362d24 727 header->checksum);
d62a17ae 728
729 if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
15569c58 730 pim_pkt_dump(__func__, pim_msg, pim_msg_size);
d62a17ae 731 }
732
733 pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to,
03c106bf 734 tolen, ifp->name);
d62a17ae 735 return 0;
529f5225
BG
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
12e41d03
DL
747}
748
d62a17ae 749static int hello_send(struct interface *ifp, uint16_t holdtime)
12e41d03 750{
d62a17ae 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
cc362d24 758 if (PIM_DEBUG_PIM_HELLO)
d62a17ae 759 zlog_debug(
cc362d24
DL
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,
d62a17ae 763 pim_ifp->pim_override_interval_msec,
b6fcc0b7 764 pim_ifp->pim_can_disable_join_suppression,
d62a17ae 765 pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
766 listcount(ifp->connected));
d62a17ae 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,
b6fcc0b7 774 pim_ifp->pim_can_disable_join_suppression);
d62a17ae 775 if (pim_tlv_size < 0) {
776 return -1;
777 }
778
779 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
780
df5dfb77
DL
781 assert(pim_msg_size >= PIM_PIM_MIN_LEN);
782 assert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
d62a17ae 783
145e4c38
DL
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);
d62a17ae 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,
11e771be 790 ifp)) {
d62a17ae 791 if (PIM_DEBUG_PIM_HELLO) {
792 zlog_debug(
793 "%s: could not send PIM message on interface %s",
15569c58 794 __func__, ifp->name);
d62a17ae 795 }
796 return -2;
797 }
798
799 return 0;
12e41d03
DL
800}
801
b279f95c 802int pim_hello_send(struct interface *ifp, uint16_t holdtime)
12e41d03 803{
11699c47 804 struct pim_interface *pim_ifp = ifp->info;
12e41d03 805
608c8870 806 if (if_is_loopback(ifp))
d62a17ae 807 return 0;
85b62aea 808
d62a17ae 809 if (hello_send(ifp, holdtime)) {
810 ++pim_ifp->pim_ifstat_hello_sendfail;
12e41d03 811
d62a17ae 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 }
12e41d03 818
11e771be 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 }
12e41d03 823
d62a17ae 824 return 0;
12e41d03
DL
825}
826
827static void hello_resched(struct interface *ifp)
828{
d62a17ae 829 struct pim_interface *pim_ifp;
830
d62a17ae 831 pim_ifp = ifp->info;
d62a17ae 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);
36417fcc 838 thread_add_timer(router->master, on_pim_hello_send, ifp,
d62a17ae 839 pim_ifp->pim_hello_period,
840 &pim_ifp->t_pim_hello_timer);
12e41d03
DL
841}
842
843/*
844 Periodic hello timer
845 */
cc9f21da 846static void on_pim_hello_send(struct thread *t)
12e41d03 847{
d62a17ae 848 struct pim_interface *pim_ifp;
849 struct interface *ifp;
12e41d03 850
d62a17ae 851 ifp = THREAD_ARG(t);
d62a17ae 852 pim_ifp = ifp->info;
12e41d03 853
d62a17ae 854 /*
855 * Schedule next hello
856 */
857 hello_resched(ifp);
12e41d03 858
d62a17ae 859 /*
860 * Send hello
861 */
cc9f21da 862 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
12e41d03
DL
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{
d62a17ae 876 struct pim_interface *pim_ifp;
12e41d03 877
d62a17ae 878 pim_ifp = ifp->info;
12e41d03 879
d62a17ae 880 /*
881 * Reset next hello timer
882 */
883 hello_resched(ifp);
12e41d03 884
d62a17ae 885 /*
886 * Immediately send hello
887 */
888 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
12e41d03
DL
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{
d62a17ae 902 struct pim_interface *pim_ifp;
903 int triggered_hello_delay_msec;
904 int random_msec;
905
d62a17ae 906 pim_ifp = ifp->info;
2aa1ca84
DS
907
908 /*
909 * No need to ever start loopback or vrf device hello's
910 */
608c8870 911 if (if_is_loopback(ifp))
2aa1ca84 912 return;
d62a17ae 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
36417fcc
DS
951 thread_add_timer_msec(router->master, on_pim_hello_send, ifp,
952 random_msec, &pim_ifp->t_pim_hello_timer);
12e41d03
DL
953}
954
955int pim_sock_add(struct interface *ifp)
956{
d62a17ae 957 struct pim_interface *pim_ifp;
958 uint32_t old_genid;
959
960 pim_ifp = ifp->info;
df5dfb77 961 assert(pim_ifp);
d62a17ae 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)
5920b3eb 995 pim_ifp->pim_generation_id = frr_weak_random();
d62a17ae 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;
12e41d03 1011}