Annotation of embedaddon/quagga/pimd/pim_pim.c, revision 1.1.1.1
1.1 misho 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
19:
20: $QuaggaId: $Format:%an, %ai, %h$ $
21: */
22:
23: #include <zebra.h>
24:
25: #include "log.h"
26: #include "thread.h"
27: #include "memory.h"
28:
29: #include "pimd.h"
30: #include "pim_pim.h"
31: #include "pim_time.h"
32: #include "pim_iface.h"
33: #include "pim_sock.h"
34: #include "pim_str.h"
35: #include "pim_util.h"
36: #include "pim_tlv.h"
37: #include "pim_neighbor.h"
38: #include "pim_hello.h"
39: #include "pim_join.h"
40: #include "pim_assert.h"
41: #include "pim_msg.h"
42:
43: static int on_pim_hello_send(struct thread *t);
44: static int pim_hello_send(struct interface *ifp,
45: uint16_t holdtime);
46:
47: static void sock_close(struct interface *ifp)
48: {
49: struct pim_interface *pim_ifp = ifp->info;
50:
51: if (PIM_DEBUG_PIM_TRACE) {
52: if (pim_ifp->t_pim_sock_read) {
53: zlog_debug("Cancelling READ event for PIM socket fd=%d on interface %s",
54: pim_ifp->pim_sock_fd,
55: ifp->name);
56: }
57: }
58: THREAD_OFF(pim_ifp->t_pim_sock_read);
59:
60: if (PIM_DEBUG_PIM_TRACE) {
61: if (pim_ifp->t_pim_hello_timer) {
62: zlog_debug("Cancelling PIM hello timer for interface %s",
63: ifp->name);
64: }
65: }
66: THREAD_OFF(pim_ifp->t_pim_hello_timer);
67:
68: if (PIM_DEBUG_PIM_TRACE) {
69: zlog_debug("Deleting PIM socket fd=%d on interface %s",
70: pim_ifp->pim_sock_fd, ifp->name);
71: }
72:
73: if (close(pim_ifp->pim_sock_fd)) {
74: zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
75: pim_ifp->pim_sock_fd, ifp->name,
76: errno, safe_strerror(errno));
77: }
78:
79: pim_ifp->pim_sock_fd = -1;
80: pim_ifp->pim_sock_creation = 0;
81:
82: zassert(pim_ifp->pim_sock_fd < 0);
83: zassert(!pim_ifp->t_pim_sock_read);
84: zassert(!pim_ifp->t_pim_hello_timer);
85: zassert(!pim_ifp->pim_sock_creation);
86: }
87:
88: void pim_sock_delete(struct interface *ifp, const char *delete_message)
89: {
90: zlog_info("PIM INTERFACE DOWN: on interface %s: %s",
91: ifp->name, delete_message);
92:
93: if (!ifp->info) {
94: zlog_err("%s: %s: but PIM not enabled on interface %s (!)",
95: __PRETTY_FUNCTION__, delete_message, ifp->name);
96: return;
97: }
98:
99: /*
100: RFC 4601: 4.3.1. Sending Hello Messages
101:
102: Before an interface goes down or changes primary IP address, a Hello
103: message with a zero HoldTime should be sent immediately (with the
104: old IP address if the IP address changed).
105: */
106: pim_hello_send(ifp, 0 /* zero-sec holdtime */);
107:
108: pim_neighbor_delete_all(ifp, delete_message);
109:
110: sock_close(ifp);
111: }
112:
113: int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
114: {
115: struct ip *ip_hdr;
116: size_t ip_hlen; /* ip header length in bytes */
117: char src_str[100];
118: char dst_str[100];
119: uint8_t *pim_msg;
120: int pim_msg_len;
121: uint8_t pim_version;
122: uint8_t pim_type;
123: uint16_t pim_checksum; /* received checksum */
124: uint16_t checksum; /* computed checksum */
125: struct pim_neighbor *neigh;
126:
127: if (!ifp->info) {
128: zlog_warn("%s: PIM not enabled on interface %s",
129: __PRETTY_FUNCTION__, ifp->name);
130: return -1;
131: }
132:
133: if (len < sizeof(*ip_hdr)) {
134: zlog_warn("PIM packet size=%zu shorter than minimum=%zu",
135: len, sizeof(*ip_hdr));
136: return -1;
137: }
138:
139: ip_hdr = (struct ip *) buf;
140:
141: pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
142: pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str, sizeof(dst_str));
143:
144: ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
145:
146: if (PIM_DEBUG_PIM_PACKETS) {
147: zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d",
148: src_str, dst_str, ifp->name, len, ip_hlen, ip_hdr->ip_p);
149: }
150:
151: if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) {
152: zlog_warn("IP packet protocol=%d is not PIM=%d",
153: ip_hdr->ip_p, PIM_IP_PROTO_PIM);
154: return -1;
155: }
156:
157: if (ip_hlen < PIM_IP_HEADER_MIN_LEN) {
158: zlog_warn("IP packet header size=%zu shorter than minimum=%d",
159: ip_hlen, PIM_IP_HEADER_MIN_LEN);
160: return -1;
161: }
162: if (ip_hlen > PIM_IP_HEADER_MAX_LEN) {
163: zlog_warn("IP packet header size=%zu greater than maximum=%d",
164: ip_hlen, PIM_IP_HEADER_MAX_LEN);
165: return -1;
166: }
167:
168: pim_msg = buf + ip_hlen;
169: pim_msg_len = len - ip_hlen;
170:
171: if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
172: pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
173: }
174:
175: if (pim_msg_len < PIM_PIM_MIN_LEN) {
176: zlog_warn("PIM message size=%d shorter than minimum=%d",
177: pim_msg_len, PIM_PIM_MIN_LEN);
178: return -1;
179: }
180:
181: pim_version = PIM_MSG_HDR_GET_VERSION(pim_msg);
182: pim_type = PIM_MSG_HDR_GET_TYPE(pim_msg);
183:
184: if (pim_version != PIM_PROTO_VERSION) {
185: zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d",
186: ifp->name, pim_version);
187: return -1;
188: }
189:
190: /* save received checksum */
191: pim_checksum = PIM_MSG_HDR_GET_CHECKSUM(pim_msg);
192:
193: /* for computing checksum */
194: *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0;
195:
196: checksum = in_cksum(pim_msg, pim_msg_len);
197: if (checksum != pim_checksum) {
198: zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
199: ifp->name, pim_checksum, checksum);
200: return -1;
201: }
202:
203: if (PIM_DEBUG_PIM_PACKETS) {
204: zlog_debug("Recv PIM packet from %s to %s on %s: ttl=%d pim_version=%d pim_type=%d pim_msg_size=%d checksum=%x",
205: src_str, dst_str, ifp->name, ip_hdr->ip_ttl,
206: pim_version, pim_type, pim_msg_len, checksum);
207: }
208:
209: if (pim_type == PIM_MSG_TYPE_REGISTER ||
210: pim_type == PIM_MSG_TYPE_REG_STOP ||
211: pim_type == PIM_MSG_TYPE_BOOTSTRAP ||
212: pim_type == PIM_MSG_TYPE_GRAFT ||
213: pim_type == PIM_MSG_TYPE_GRAFT_ACK ||
214: pim_type == PIM_MSG_TYPE_CANDIDATE)
215: {
216: if (PIM_DEBUG_PIM_PACKETS) {
217: zlog_debug("Recv PIM packet type %d which is not currently understood",
218: pim_type);
219: }
220: return -1;
221: }
222:
223: if (pim_type == PIM_MSG_TYPE_HELLO) {
224: int result = pim_hello_recv(ifp,
225: ip_hdr->ip_src,
226: pim_msg + PIM_MSG_HEADER_LEN,
227: pim_msg_len - PIM_MSG_HEADER_LEN);
228: return result;
229: }
230:
231: neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
232: if (!neigh) {
233: zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
234: __FILE__, __PRETTY_FUNCTION__,
235: pim_type, src_str, ifp->name);
236: return -1;
237: }
238:
239: switch (pim_type) {
240: case PIM_MSG_TYPE_JOIN_PRUNE:
241: return pim_joinprune_recv(ifp, neigh,
242: ip_hdr->ip_src,
243: pim_msg + PIM_MSG_HEADER_LEN,
244: pim_msg_len - PIM_MSG_HEADER_LEN);
245: case PIM_MSG_TYPE_ASSERT:
246: return pim_assert_recv(ifp, neigh,
247: ip_hdr->ip_src,
248: pim_msg + PIM_MSG_HEADER_LEN,
249: pim_msg_len - PIM_MSG_HEADER_LEN);
250: default:
251: zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s",
252: __FILE__, __PRETTY_FUNCTION__,
253: pim_type, src_str, ifp->name);
254: }
255:
256: return -1;
257: }
258:
259: static void pim_sock_read_on(struct interface *ifp);
260:
261: static int pim_sock_read(struct thread *t)
262: {
263: struct interface *ifp;
264: struct pim_interface *pim_ifp;
265: int fd;
266: struct sockaddr_in from;
267: struct sockaddr_in to;
268: socklen_t fromlen = sizeof(from);
269: socklen_t tolen = sizeof(to);
270: uint8_t buf[PIM_PIM_BUFSIZE_READ];
271: int len;
272: ifindex_t ifindex = -1;
273: int result = -1; /* defaults to bad */
274:
275: zassert(t);
276:
277: ifp = THREAD_ARG(t);
278: zassert(ifp);
279:
280: fd = THREAD_FD(t);
281:
282: pim_ifp = ifp->info;
283: zassert(pim_ifp);
284:
285: zassert(fd == pim_ifp->pim_sock_fd);
286:
287: len = pim_socket_recvfromto(fd, buf, sizeof(buf),
288: &from, &fromlen,
289: &to, &tolen,
290: &ifindex);
291: if (len < 0) {
292: zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s",
293: fd, errno, safe_strerror(errno));
294: goto done;
295: }
296:
297: if (PIM_DEBUG_PIM_PACKETS) {
298: char from_str[100];
299: char to_str[100];
300:
301: if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str)))
302: sprintf(from_str, "<from?>");
303: if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str)))
304: sprintf(to_str, "<to?>");
305:
306: zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)",
307: len, from_str, to_str, fd, ifindex, ifp->ifindex);
308: }
309:
310: if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
311: pim_pkt_dump(__PRETTY_FUNCTION__, buf, len);
312: }
313:
314: #ifdef PIM_CHECK_RECV_IFINDEX_SANITY
315: /* ifindex sanity check */
316: if (ifindex != (int) ifp->ifindex) {
317: char from_str[100];
318: char to_str[100];
319: struct interface *recv_ifp;
320:
321: if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str)))
322: sprintf(from_str, "<from?>");
323: if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str)))
324: sprintf(to_str, "<to?>");
325:
326: recv_ifp = if_lookup_by_index(ifindex);
327: if (recv_ifp) {
328: zassert(ifindex == (int) recv_ifp->ifindex);
329: }
330:
331: #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
332: zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
333: from_str, to_str, fd,
334: ifindex, recv_ifp ? recv_ifp->name : "<if-notfound>",
335: ifp->ifindex, ifp->name);
336: #endif
337: goto done;
338: }
339: #endif
340:
341: int fail = pim_pim_packet(ifp, buf, len);
342: if (fail) {
343: zlog_warn("%s: pim_pim_packet() return=%d",
344: __PRETTY_FUNCTION__, fail);
345: goto done;
346: }
347:
348: result = 0; /* good */
349:
350: done:
351: pim_sock_read_on(ifp);
352:
353: if (result) {
354: ++pim_ifp->pim_ifstat_hello_recvfail;
355: }
356:
357: return result;
358: }
359:
360: static void pim_sock_read_on(struct interface *ifp)
361: {
362: struct pim_interface *pim_ifp;
363:
364: zassert(ifp);
365: zassert(ifp->info);
366:
367: pim_ifp = ifp->info;
368:
369: if (PIM_DEBUG_PIM_TRACE) {
370: zlog_debug("Scheduling READ event on PIM socket fd=%d",
371: pim_ifp->pim_sock_fd);
372: }
373: pim_ifp->t_pim_sock_read = 0;
374: zassert(!pim_ifp->t_pim_sock_read);
375: THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
376: pim_ifp->pim_sock_fd);
377: }
378:
379: static int pim_sock_open(struct in_addr ifaddr, ifindex_t ifindex)
380: {
381: int fd;
382:
383: fd = pim_socket_mcast(IPPROTO_PIM, ifaddr, 0 /* loop=false */);
384: if (fd < 0)
385: return -1;
386:
387: if (pim_socket_join(fd, qpim_all_pim_routers_addr, ifaddr, ifindex)) {
388: close(fd);
389: return -2;
390: }
391:
392: return fd;
393: }
394:
395: void pim_ifstat_reset(struct interface *ifp)
396: {
397: struct pim_interface *pim_ifp;
398:
399: zassert(ifp);
400:
401: pim_ifp = ifp->info;
402: if (!pim_ifp) {
403: return;
404: }
405:
406: pim_ifp->pim_ifstat_start = pim_time_monotonic_sec();
407: pim_ifp->pim_ifstat_hello_sent = 0;
408: pim_ifp->pim_ifstat_hello_sendfail = 0;
409: pim_ifp->pim_ifstat_hello_recv = 0;
410: pim_ifp->pim_ifstat_hello_recvfail = 0;
411: }
412:
413: void pim_sock_reset(struct interface *ifp)
414: {
415: struct pim_interface *pim_ifp;
416:
417: zassert(ifp);
418: zassert(ifp->info);
419:
420: pim_ifp = ifp->info;
421:
422: pim_ifp->primary_address = pim_find_primary_addr(ifp);
423:
424: pim_ifp->pim_sock_fd = -1;
425: pim_ifp->pim_sock_creation = 0;
426: pim_ifp->t_pim_sock_read = 0;
427:
428: pim_ifp->t_pim_hello_timer = 0;
429: pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
430: pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
431: pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
432: pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
433: pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
434: pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
435: if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
436: PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
437: }
438: else {
439: PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options);
440: }
441:
442: /* neighbors without lan_delay */
443: pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
444: pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0;
445: pim_ifp->pim_neighbors_highest_override_interval_msec = 0;
446:
447: /* DR Election */
448: pim_ifp->pim_dr_election_last = 0; /* timestamp */
449: pim_ifp->pim_dr_election_count = 0;
450: pim_ifp->pim_dr_election_changes = 0;
451: pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */
452: pim_ifp->pim_dr_addr = pim_ifp->primary_address;
453:
454: pim_ifstat_reset(ifp);
455: }
456:
457: int pim_msg_send(int fd,
458: struct in_addr dst,
459: uint8_t *pim_msg,
460: int pim_msg_size,
461: const char *ifname)
462: {
463: ssize_t sent;
464: struct sockaddr_in to;
465: socklen_t tolen;
466:
467: if (PIM_DEBUG_PIM_PACKETS) {
468: char dst_str[100];
469: pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
470: zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
471: __PRETTY_FUNCTION__,
472: dst_str, ifname, pim_msg_size,
473: *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg));
474: }
475:
476: #if 0
477: memset(&to, 0, sizeof(to));
478: #endif
479: to.sin_family = AF_INET;
480: to.sin_addr = dst;
481: #if 0
482: to.sin_port = htons(0);
483: #endif
484: tolen = sizeof(to);
485:
486: if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
487: pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
488: }
489:
490: sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT,
491: (struct sockaddr *)&to, tolen);
492: if (sent != (ssize_t) pim_msg_size) {
493: int e = errno;
494: char dst_str[100];
495: pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
496: if (sent < 0) {
497: zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
498: __PRETTY_FUNCTION__,
499: dst_str, ifname, fd, pim_msg_size,
500: e, safe_strerror(e));
501: }
502: else {
503: zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
504: __PRETTY_FUNCTION__,
505: dst_str, ifname, fd,
506: pim_msg_size, sent);
507: }
508: return -1;
509: }
510:
511: return 0;
512: }
513:
514: static int hello_send(struct interface *ifp,
515: uint16_t holdtime)
516: {
517: uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE];
518: struct pim_interface *pim_ifp;
519: int pim_tlv_size;
520: int pim_msg_size;
521:
522: pim_ifp = ifp->info;
523:
524: if (PIM_DEBUG_PIM_HELLO) {
525: char dst_str[100];
526: pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str));
527: 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",
528: __PRETTY_FUNCTION__,
529: dst_str, ifp->name,
530: holdtime,
531: pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec,
532: PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
533: pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
534: listcount(ifp->connected));
535: }
536:
537: pim_tlv_size = pim_hello_build_tlv(ifp->name,
538: pim_msg + PIM_PIM_MIN_LEN,
539: sizeof(pim_msg) - PIM_PIM_MIN_LEN,
540: holdtime,
541: pim_ifp->pim_dr_priority,
542: pim_ifp->pim_generation_id,
543: pim_ifp->pim_propagation_delay_msec,
544: pim_ifp->pim_override_interval_msec,
545: PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
546: ifp->connected);
547: if (pim_tlv_size < 0) {
548: return -1;
549: }
550:
551: pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
552:
553: zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
554: zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
555:
556: pim_msg_build_header(pim_msg, pim_msg_size,
557: PIM_MSG_TYPE_HELLO);
558:
559: if (pim_msg_send(pim_ifp->pim_sock_fd,
560: qpim_all_pim_routers_addr,
561: pim_msg,
562: pim_msg_size,
563: ifp->name)) {
564: if (PIM_DEBUG_PIM_HELLO) {
565: zlog_debug("%s: could not send PIM message on interface %s",
566: __PRETTY_FUNCTION__, ifp->name);
567: }
568: return -2;
569: }
570:
571: return 0;
572: }
573:
574: static int pim_hello_send(struct interface *ifp,
575: uint16_t holdtime)
576: {
577: struct pim_interface *pim_ifp;
578:
579: zassert(ifp);
580: pim_ifp = ifp->info;
581: zassert(pim_ifp);
582:
583: if (hello_send(ifp, holdtime)) {
584: ++pim_ifp->pim_ifstat_hello_sendfail;
585:
586: if (PIM_DEBUG_PIM_HELLO) {
587: zlog_warn("Could not send PIM hello on interface %s",
588: ifp->name);
589: }
590: return -1;
591: }
592:
593: ++pim_ifp->pim_ifstat_hello_sent;
594:
595: return 0;
596: }
597:
598: static void hello_resched(struct interface *ifp)
599: {
600: struct pim_interface *pim_ifp;
601:
602: zassert(ifp);
603: pim_ifp = ifp->info;
604: zassert(pim_ifp);
605:
606: if (PIM_DEBUG_PIM_HELLO) {
607: zlog_debug("Rescheduling %d sec hello on interface %s",
608: pim_ifp->pim_hello_period, ifp->name);
609: }
610: THREAD_OFF(pim_ifp->t_pim_hello_timer);
611: THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer,
612: on_pim_hello_send,
613: ifp, pim_ifp->pim_hello_period);
614: }
615:
616: /*
617: Periodic hello timer
618: */
619: static int on_pim_hello_send(struct thread *t)
620: {
621: struct pim_interface *pim_ifp;
622: struct interface *ifp;
623:
624: zassert(t);
625: ifp = THREAD_ARG(t);
626: zassert(ifp);
627:
628: pim_ifp = ifp->info;
629:
630: /*
631: * Schedule next hello
632: */
633: pim_ifp->t_pim_hello_timer = 0;
634: hello_resched(ifp);
635:
636: /*
637: * Send hello
638: */
639: return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
640: }
641:
642: /*
643: RFC 4601: 4.3.1. Sending Hello Messages
644:
645: Thus, if a router needs to send a Join/Prune or Assert message on an
646: interface on which it has not yet sent a Hello message with the
647: currently configured IP address, then it MUST immediately send the
648: relevant Hello message without waiting for the Hello Timer to
649: expire, followed by the Join/Prune or Assert message.
650: */
651: void pim_hello_restart_now(struct interface *ifp)
652: {
653: struct pim_interface *pim_ifp;
654:
655: zassert(ifp);
656: pim_ifp = ifp->info;
657: zassert(pim_ifp);
658:
659: /*
660: * Reset next hello timer
661: */
662: hello_resched(ifp);
663:
664: /*
665: * Immediately send hello
666: */
667: pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
668: }
669:
670: /*
671: RFC 4601: 4.3.1. Sending Hello Messages
672:
673: To allow new or rebooting routers to learn of PIM neighbors quickly,
674: when a Hello message is received from a new neighbor, or a Hello
675: message with a new GenID is received from an existing neighbor, a
676: new Hello message should be sent on this interface after a
677: randomized delay between 0 and Triggered_Hello_Delay.
678: */
679: void pim_hello_restart_triggered(struct interface *ifp)
680: {
681: struct pim_interface *pim_ifp;
682: int triggered_hello_delay_msec;
683: int random_msec;
684:
685: zassert(ifp);
686: pim_ifp = ifp->info;
687: zassert(pim_ifp);
688:
689: triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
690:
691: if (pim_ifp->t_pim_hello_timer) {
692: long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
693: if (remain_msec <= triggered_hello_delay_msec) {
694: /* Rescheduling hello would increase the delay, then it's faster
695: to just wait for the scheduled periodic hello. */
696: return;
697: }
698:
699: THREAD_OFF(pim_ifp->t_pim_hello_timer);
700: pim_ifp->t_pim_hello_timer = 0;
701: }
702: zassert(!pim_ifp->t_pim_hello_timer);
703:
704: random_msec = random() % (triggered_hello_delay_msec + 1);
705:
706: if (PIM_DEBUG_PIM_HELLO) {
707: zlog_debug("Scheduling %d msec triggered hello on interface %s",
708: random_msec, ifp->name);
709: }
710:
711: THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer,
712: on_pim_hello_send,
713: ifp, random_msec);
714: }
715:
716: int pim_sock_add(struct interface *ifp)
717: {
718: struct pim_interface *pim_ifp;
719: struct in_addr ifaddr;
720: uint32_t old_genid;
721:
722: pim_ifp = ifp->info;
723: zassert(pim_ifp);
724:
725: if (pim_ifp->pim_sock_fd >= 0) {
726: zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
727: pim_ifp->pim_sock_fd, ifp->name);
728: return -1;
729: }
730:
731: ifaddr = pim_ifp->primary_address;
732:
733: pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
734: if (pim_ifp->pim_sock_fd < 0) {
735: zlog_warn("Could not open PIM socket on interface %s",
736: ifp->name);
737: return -2;
738: }
739:
740: pim_ifp->t_pim_sock_read = 0;
741: pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
742:
743: /*
744: * Just ensure that the new generation id
745: * actually chooses something different.
746: * Actually ran across a case where this
747: * happened, pre-switch to random().
748: * While this is unlikely to happen now
749: * let's make sure it doesn't.
750: */
751: old_genid = pim_ifp->pim_generation_id;
752:
753: while (old_genid == pim_ifp->pim_generation_id)
754: pim_ifp->pim_generation_id = random();
755:
756: zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d",
757: ifp->name, ifp->ifindex);
758:
759: /*
760: * Start receiving PIM messages
761: */
762: pim_sock_read_on(ifp);
763:
764: /*
765: * Start sending PIM hello's
766: */
767: pim_hello_restart_triggered(ifp);
768:
769: return 0;
770: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>