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