]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_pim.c
Merge pull request #486 from LabNConsulting/working/3.0/patch/issue483
[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;
12e41d03
DL
386 THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
387 pim_ifp->pim_sock_fd);
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
630 pim_tlv_size = pim_hello_build_tlv(ifp->name,
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,
638 PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
639 ifp->connected);
640 if (pim_tlv_size < 0) {
641 return -1;
642 }
643
644 pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
645
646 zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
647 zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
648
f8e7d799 649 pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO);
12e41d03
DL
650
651 if (pim_msg_send(pim_ifp->pim_sock_fd,
4df01a4e 652 pim_ifp->primary_address,
12e41d03
DL
653 qpim_all_pim_routers_addr,
654 pim_msg,
655 pim_msg_size,
656 ifp->name)) {
aea6cb94
DS
657 if (PIM_DEBUG_PIM_HELLO) {
658 zlog_debug("%s: could not send PIM message on interface %s",
659 __PRETTY_FUNCTION__, ifp->name);
660 }
12e41d03
DL
661 return -2;
662 }
663
664 return 0;
665}
666
667static int pim_hello_send(struct interface *ifp,
668 uint16_t holdtime)
669{
670 struct pim_interface *pim_ifp;
671
672 zassert(ifp);
673 pim_ifp = ifp->info;
674 zassert(pim_ifp);
675
85b62aea
DS
676 if (if_is_loopback (ifp))
677 return 0;
678
12e41d03
DL
679 if (hello_send(ifp, holdtime)) {
680 ++pim_ifp->pim_ifstat_hello_sendfail;
681
aea6cb94
DS
682 if (PIM_DEBUG_PIM_HELLO) {
683 zlog_warn("Could not send PIM hello on interface %s",
684 ifp->name);
685 }
12e41d03
DL
686 return -1;
687 }
688
689 ++pim_ifp->pim_ifstat_hello_sent;
690
691 return 0;
692}
693
694static void hello_resched(struct interface *ifp)
695{
696 struct pim_interface *pim_ifp;
697
698 zassert(ifp);
699 pim_ifp = ifp->info;
700 zassert(pim_ifp);
701
aea6cb94 702 if (PIM_DEBUG_PIM_HELLO) {
12e41d03
DL
703 zlog_debug("Rescheduling %d sec hello on interface %s",
704 pim_ifp->pim_hello_period, ifp->name);
705 }
706 THREAD_OFF(pim_ifp->t_pim_hello_timer);
707 THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
708 on_pim_hello_send,
709 ifp, pim_ifp->pim_hello_period);
710}
711
712/*
713 Periodic hello timer
714 */
715static int on_pim_hello_send(struct thread *t)
716{
717 struct pim_interface *pim_ifp;
718 struct interface *ifp;
719
12e41d03 720 ifp = THREAD_ARG(t);
12e41d03
DL
721
722 pim_ifp = ifp->info;
723
724 /*
725 * Schedule next hello
726 */
59ba0ac3 727 pim_ifp->t_pim_hello_timer = NULL;
12e41d03
DL
728 hello_resched(ifp);
729
730 /*
731 * Send hello
732 */
733 return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
734}
735
736/*
737 RFC 4601: 4.3.1. Sending Hello Messages
738
739 Thus, if a router needs to send a Join/Prune or Assert message on an
740 interface on which it has not yet sent a Hello message with the
741 currently configured IP address, then it MUST immediately send the
742 relevant Hello message without waiting for the Hello Timer to
743 expire, followed by the Join/Prune or Assert message.
744 */
745void pim_hello_restart_now(struct interface *ifp)
746{
747 struct pim_interface *pim_ifp;
748
749 zassert(ifp);
750 pim_ifp = ifp->info;
751 zassert(pim_ifp);
752
753 /*
754 * Reset next hello timer
755 */
756 hello_resched(ifp);
757
758 /*
759 * Immediately send hello
760 */
761 pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
762}
763
764/*
765 RFC 4601: 4.3.1. Sending Hello Messages
766
767 To allow new or rebooting routers to learn of PIM neighbors quickly,
768 when a Hello message is received from a new neighbor, or a Hello
769 message with a new GenID is received from an existing neighbor, a
770 new Hello message should be sent on this interface after a
771 randomized delay between 0 and Triggered_Hello_Delay.
772 */
773void pim_hello_restart_triggered(struct interface *ifp)
774{
775 struct pim_interface *pim_ifp;
776 int triggered_hello_delay_msec;
777 int random_msec;
778
779 zassert(ifp);
780 pim_ifp = ifp->info;
781 zassert(pim_ifp);
782
cf3cd99f
DS
783 /*
784 * There exists situations where we have the a RPF out this
785 * interface, but we haven't formed a neighbor yet. This
786 * happens especially during interface flaps. While
787 * we would like to handle this more gracefully in other
788 * parts of the code. In order to get us up and running
789 * let's just send the hello immediate'ish
790 * This should be revisited when we get nexthop tracking
791 * in and when we have a better handle on safely
792 * handling the rpf information for upstreams that
793 * we cannot legally reach yet.
794 */
795 triggered_hello_delay_msec = 1;
796 //triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
12e41d03
DL
797
798 if (pim_ifp->t_pim_hello_timer) {
799 long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
800 if (remain_msec <= triggered_hello_delay_msec) {
801 /* Rescheduling hello would increase the delay, then it's faster
802 to just wait for the scheduled periodic hello. */
803 return;
804 }
805
806 THREAD_OFF(pim_ifp->t_pim_hello_timer);
59ba0ac3 807 pim_ifp->t_pim_hello_timer = NULL;
12e41d03 808 }
12e41d03 809
cf3cd99f
DS
810 random_msec = triggered_hello_delay_msec;
811 //random_msec = random() % (triggered_hello_delay_msec + 1);
12e41d03 812
aea6cb94 813 if (PIM_DEBUG_PIM_HELLO) {
12e41d03
DL
814 zlog_debug("Scheduling %d msec triggered hello on interface %s",
815 random_msec, ifp->name);
816 }
817
818 THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
819 on_pim_hello_send,
820 ifp, random_msec);
821}
822
823int pim_sock_add(struct interface *ifp)
824{
825 struct pim_interface *pim_ifp;
c29c0f61 826 uint32_t old_genid;
12e41d03
DL
827
828 pim_ifp = ifp->info;
829 zassert(pim_ifp);
830
831 if (pim_ifp->pim_sock_fd >= 0) {
def1e807
DS
832 if (PIM_DEBUG_PIM_PACKETS)
833 zlog_debug("Can't recreate existing PIM socket fd=%d for interface %s",
834 pim_ifp->pim_sock_fd, ifp->name);
12e41d03
DL
835 return -1;
836 }
837
e5dfe687 838 pim_ifp->pim_sock_fd = pim_sock_open(ifp);
12e41d03 839 if (pim_ifp->pim_sock_fd < 0) {
def1e807
DS
840 if (PIM_DEBUG_PIM_PACKETS)
841 zlog_debug("Could not open PIM socket on interface %s",
842 ifp->name);
12e41d03
DL
843 return -2;
844 }
845
4df01a4e
DS
846 pim_socket_ip_hdr (pim_ifp->pim_sock_fd);
847
59ba0ac3 848 pim_ifp->t_pim_sock_read = NULL;
12e41d03
DL
849 pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
850
c29c0f61
DS
851 /*
852 * Just ensure that the new generation id
853 * actually chooses something different.
854 * Actually ran across a case where this
855 * happened, pre-switch to random().
856 * While this is unlikely to happen now
857 * let's make sure it doesn't.
858 */
859 old_genid = pim_ifp->pim_generation_id;
860
861 while (old_genid == pim_ifp->pim_generation_id)
862 pim_ifp->pim_generation_id = random();
12e41d03
DL
863
864 zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
865 ifp->name, ifp->ifindex);
866
867 /*
868 * Start receiving PIM messages
869 */
870 pim_sock_read_on(ifp);
871
872 /*
873 * Start sending PIM hello's
874 */
875 pim_hello_restart_triggered(ifp);
876
877 return 0;
878}