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