Annotation of embedaddon/quagga/pimd/pim_pim.c, revision 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>