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