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