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