Annotation of embedaddon/quagga/pimd/pim_hello.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:
! 27: #include "pimd.h"
! 28: #include "pim_pim.h"
! 29: #include "pim_str.h"
! 30: #include "pim_tlv.h"
! 31: #include "pim_util.h"
! 32: #include "pim_hello.h"
! 33: #include "pim_iface.h"
! 34: #include "pim_neighbor.h"
! 35: #include "pim_upstream.h"
! 36:
! 37: static void on_trace(const char *label,
! 38: struct interface *ifp, struct in_addr src)
! 39: {
! 40: if (PIM_DEBUG_PIM_TRACE) {
! 41: char src_str[100];
! 42: pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
! 43: zlog_debug("%s: from %s on %s",
! 44: label, src_str, ifp->name);
! 45: }
! 46: }
! 47:
! 48: static void tlv_trace_bool(const char *label, const char *tlv_name,
! 49: const char *ifname, struct in_addr src_addr,
! 50: int isset, int value)
! 51: {
! 52: if (isset) {
! 53: char src_str[100];
! 54: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 55: zlog_debug("%s: PIM hello option from %s on interface %s: %s=%d",
! 56: label,
! 57: src_str, ifname,
! 58: tlv_name, value);
! 59: }
! 60: }
! 61:
! 62: static void tlv_trace_uint16(const char *label, const char *tlv_name,
! 63: const char *ifname, struct in_addr src_addr,
! 64: int isset, uint16_t value)
! 65: {
! 66: if (isset) {
! 67: char src_str[100];
! 68: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 69: zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
! 70: label,
! 71: src_str, ifname,
! 72: tlv_name, value);
! 73: }
! 74: }
! 75:
! 76: static void tlv_trace_uint32(const char *label, const char *tlv_name,
! 77: const char *ifname, struct in_addr src_addr,
! 78: int isset, uint32_t value)
! 79: {
! 80: if (isset) {
! 81: char src_str[100];
! 82: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 83: zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
! 84: label,
! 85: src_str, ifname,
! 86: tlv_name, value);
! 87: }
! 88: }
! 89:
! 90: static void tlv_trace_uint32_hex(const char *label, const char *tlv_name,
! 91: const char *ifname, struct in_addr src_addr,
! 92: int isset, uint32_t value)
! 93: {
! 94: if (isset) {
! 95: char src_str[100];
! 96: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 97: zlog_debug("%s: PIM hello option from %s on interface %s: %s=%08x",
! 98: label,
! 99: src_str, ifname,
! 100: tlv_name, value);
! 101: }
! 102: }
! 103:
! 104: #if 0
! 105: static void tlv_trace(const char *label, const char *tlv_name,
! 106: const char *ifname, struct in_addr src_addr,
! 107: int isset)
! 108: {
! 109: if (isset) {
! 110: char src_str[100];
! 111: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 112: zlog_debug("%s: PIM hello option from %s on interface %s: %s",
! 113: label,
! 114: src_str, ifname,
! 115: tlv_name);
! 116: }
! 117: }
! 118: #endif
! 119:
! 120: static void tlv_trace_list(const char *label, const char *tlv_name,
! 121: const char *ifname, struct in_addr src_addr,
! 122: int isset, struct list *addr_list)
! 123: {
! 124: if (isset) {
! 125: char src_str[100];
! 126: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 127: zlog_debug("%s: PIM hello option from %s on interface %s: %s size=%d list=%p",
! 128: label,
! 129: src_str, ifname,
! 130: tlv_name,
! 131: addr_list ? ((int) listcount(addr_list)) : -1,
! 132: (void *) addr_list);
! 133: }
! 134: }
! 135:
! 136: #define FREE_ADDR_LIST \
! 137: if (hello_option_addr_list) { \
! 138: list_delete(hello_option_addr_list); \
! 139: }
! 140:
! 141: #define FREE_ADDR_LIST_THEN_RETURN(code) \
! 142: { \
! 143: FREE_ADDR_LIST \
! 144: return (code); \
! 145: }
! 146:
! 147: int pim_hello_recv(struct interface *ifp,
! 148: struct in_addr src_addr,
! 149: uint8_t *tlv_buf, int tlv_buf_size)
! 150: {
! 151: struct pim_interface *pim_ifp;
! 152: struct pim_neighbor *neigh;
! 153: uint8_t *tlv_curr;
! 154: uint8_t *tlv_pastend;
! 155: pim_hello_options hello_options = 0; /* bit array recording options found */
! 156: uint16_t hello_option_holdtime = 0;
! 157: uint16_t hello_option_propagation_delay = 0;
! 158: uint16_t hello_option_override_interval = 0;
! 159: uint32_t hello_option_dr_priority = 0;
! 160: uint32_t hello_option_generation_id = 0;
! 161: struct list *hello_option_addr_list = 0;
! 162:
! 163: if (PIM_DEBUG_PIM_HELLO)
! 164: on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
! 165:
! 166: pim_ifp = ifp->info;
! 167: zassert(pim_ifp);
! 168:
! 169: ++pim_ifp->pim_ifstat_hello_recv;
! 170:
! 171: /*
! 172: Parse PIM hello TLVs
! 173: */
! 174: zassert(tlv_buf_size >= 0);
! 175: tlv_curr = tlv_buf;
! 176: tlv_pastend = tlv_buf + tlv_buf_size;
! 177:
! 178: while (tlv_curr < tlv_pastend) {
! 179: uint16_t option_type;
! 180: uint16_t option_len;
! 181: int remain = tlv_pastend - tlv_curr;
! 182:
! 183: if (remain < PIM_TLV_MIN_SIZE) {
! 184: if (PIM_DEBUG_PIM_HELLO) {
! 185: char src_str[100];
! 186: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 187: zlog_debug("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s",
! 188: __PRETTY_FUNCTION__,
! 189: remain, PIM_TLV_MIN_SIZE,
! 190: src_str, ifp->name);
! 191: }
! 192: FREE_ADDR_LIST_THEN_RETURN(-1);
! 193: }
! 194:
! 195: option_type = PIM_TLV_GET_TYPE(tlv_curr);
! 196: tlv_curr += PIM_TLV_TYPE_SIZE;
! 197: option_len = PIM_TLV_GET_LENGTH(tlv_curr);
! 198: tlv_curr += PIM_TLV_LENGTH_SIZE;
! 199:
! 200: if ((tlv_curr + option_len) > tlv_pastend) {
! 201: if (PIM_DEBUG_PIM_HELLO) {
! 202: char src_str[100];
! 203: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 204: zlog_debug("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s",
! 205: __PRETTY_FUNCTION__,
! 206: option_type, option_len, tlv_pastend - tlv_curr,
! 207: src_str, ifp->name);
! 208: }
! 209: FREE_ADDR_LIST_THEN_RETURN(-2);
! 210: }
! 211:
! 212: if (PIM_DEBUG_PIM_HELLO) {
! 213: char src_str[100];
! 214: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 215: zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s",
! 216: __PRETTY_FUNCTION__,
! 217: remain,
! 218: option_type, option_len,
! 219: src_str, ifp->name);
! 220: }
! 221:
! 222: switch (option_type) {
! 223: case PIM_MSG_OPTION_TYPE_HOLDTIME:
! 224: if (pim_tlv_parse_holdtime(ifp->name, src_addr,
! 225: &hello_options,
! 226: &hello_option_holdtime,
! 227: option_len,
! 228: tlv_curr)) {
! 229: FREE_ADDR_LIST_THEN_RETURN(-3);
! 230: }
! 231: break;
! 232: case PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY:
! 233: if (pim_tlv_parse_lan_prune_delay(ifp->name, src_addr,
! 234: &hello_options,
! 235: &hello_option_propagation_delay,
! 236: &hello_option_override_interval,
! 237: option_len,
! 238: tlv_curr)) {
! 239: FREE_ADDR_LIST_THEN_RETURN(-4);
! 240: }
! 241: break;
! 242: case PIM_MSG_OPTION_TYPE_DR_PRIORITY:
! 243: if (pim_tlv_parse_dr_priority(ifp->name, src_addr,
! 244: &hello_options,
! 245: &hello_option_dr_priority,
! 246: option_len,
! 247: tlv_curr)) {
! 248: FREE_ADDR_LIST_THEN_RETURN(-5);
! 249: }
! 250: break;
! 251: case PIM_MSG_OPTION_TYPE_GENERATION_ID:
! 252: if (pim_tlv_parse_generation_id(ifp->name, src_addr,
! 253: &hello_options,
! 254: &hello_option_generation_id,
! 255: option_len,
! 256: tlv_curr)) {
! 257: FREE_ADDR_LIST_THEN_RETURN(-6);
! 258: }
! 259: break;
! 260: case PIM_MSG_OPTION_TYPE_ADDRESS_LIST:
! 261: if (pim_tlv_parse_addr_list(ifp->name, src_addr,
! 262: &hello_options,
! 263: &hello_option_addr_list,
! 264: option_len,
! 265: tlv_curr)) {
! 266: return -7;
! 267: }
! 268: break;
! 269: case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH:
! 270: if (PIM_DEBUG_PIM_HELLO) {
! 271: char src_str[100];
! 272: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 273: zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s",
! 274: __PRETTY_FUNCTION__,
! 275: option_type, option_len,
! 276: src_str, ifp->name);
! 277: }
! 278: break;
! 279: default:
! 280: if (PIM_DEBUG_PIM_HELLO) {
! 281: char src_str[100];
! 282: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 283: zlog_debug("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s",
! 284: __PRETTY_FUNCTION__,
! 285: option_type, option_len,
! 286: src_str, ifp->name);
! 287: }
! 288: }
! 289:
! 290: tlv_curr += option_len;
! 291: }
! 292:
! 293: /*
! 294: Check received PIM hello options
! 295: */
! 296:
! 297: if (PIM_DEBUG_PIM_HELLO) {
! 298: tlv_trace_uint16(__PRETTY_FUNCTION__, "holdtime",
! 299: ifp->name, src_addr,
! 300: PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME),
! 301: hello_option_holdtime);
! 302: tlv_trace_uint16(__PRETTY_FUNCTION__, "propagation_delay",
! 303: ifp->name, src_addr,
! 304: PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY),
! 305: hello_option_propagation_delay);
! 306: tlv_trace_uint16(__PRETTY_FUNCTION__, "override_interval",
! 307: ifp->name, src_addr,
! 308: PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY),
! 309: hello_option_override_interval);
! 310: tlv_trace_bool(__PRETTY_FUNCTION__, "can_disable_join_suppression",
! 311: ifp->name, src_addr,
! 312: PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY),
! 313: PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION));
! 314: tlv_trace_uint32(__PRETTY_FUNCTION__, "dr_priority",
! 315: ifp->name, src_addr,
! 316: PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_DR_PRIORITY),
! 317: hello_option_dr_priority);
! 318: tlv_trace_uint32_hex(__PRETTY_FUNCTION__, "generation_id",
! 319: ifp->name, src_addr,
! 320: PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_GENERATION_ID),
! 321: hello_option_generation_id);
! 322: tlv_trace_list(__PRETTY_FUNCTION__, "address_list",
! 323: ifp->name, src_addr,
! 324: PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_ADDRESS_LIST),
! 325: hello_option_addr_list);
! 326: }
! 327:
! 328: if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
! 329: if (PIM_DEBUG_PIM_HELLO) {
! 330: char src_str[100];
! 331: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 332: zlog_debug("%s: PIM hello missing holdtime from %s on interface %s",
! 333: __PRETTY_FUNCTION__,
! 334: src_str, ifp->name);
! 335: }
! 336: }
! 337:
! 338: /*
! 339: New neighbor?
! 340: */
! 341:
! 342: neigh = pim_neighbor_find(ifp, src_addr);
! 343: if (!neigh) {
! 344: /* Add as new neighbor */
! 345:
! 346: neigh = pim_neighbor_add(ifp, src_addr,
! 347: hello_options,
! 348: hello_option_holdtime,
! 349: hello_option_propagation_delay,
! 350: hello_option_override_interval,
! 351: hello_option_dr_priority,
! 352: hello_option_generation_id,
! 353: hello_option_addr_list);
! 354: if (!neigh) {
! 355: if (PIM_DEBUG_PIM_HELLO) {
! 356: char src_str[100];
! 357: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 358: zlog_warn("%s: failure creating PIM neighbor %s on interface %s",
! 359: __PRETTY_FUNCTION__,
! 360: src_str, ifp->name);
! 361: }
! 362: FREE_ADDR_LIST_THEN_RETURN(-8);
! 363: }
! 364:
! 365: /* actual addr list has been saved under neighbor */
! 366: return 0;
! 367: }
! 368:
! 369: /*
! 370: Received generation ID ?
! 371: */
! 372:
! 373: if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_GENERATION_ID)) {
! 374: /* GenID mismatch ? */
! 375: if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID) ||
! 376: (hello_option_generation_id != neigh->generation_id)) {
! 377:
! 378: /* GenID changed */
! 379:
! 380: pim_upstream_rpf_genid_changed(neigh->source_addr);
! 381:
! 382: /* GenID mismatch, then replace neighbor */
! 383:
! 384: if (PIM_DEBUG_PIM_HELLO) {
! 385: char src_str[100];
! 386: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 387: zlog_debug("%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s",
! 388: __PRETTY_FUNCTION__,
! 389: hello_option_generation_id,
! 390: neigh->generation_id,
! 391: src_str, ifp->name);
! 392: }
! 393:
! 394: pim_upstream_rpf_genid_changed(neigh->source_addr);
! 395:
! 396: pim_neighbor_delete(ifp, neigh, "GenID mismatch");
! 397: neigh = pim_neighbor_add(ifp, src_addr,
! 398: hello_options,
! 399: hello_option_holdtime,
! 400: hello_option_propagation_delay,
! 401: hello_option_override_interval,
! 402: hello_option_dr_priority,
! 403: hello_option_generation_id,
! 404: hello_option_addr_list);
! 405: if (!neigh) {
! 406: if (PIM_DEBUG_PIM_HELLO) {
! 407: char src_str[100];
! 408: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 409: zlog_debug("%s: failure re-creating PIM neighbor %s on interface %s",
! 410: __PRETTY_FUNCTION__,
! 411: src_str, ifp->name);
! 412: }
! 413: FREE_ADDR_LIST_THEN_RETURN(-9);
! 414: }
! 415: /* actual addr list is saved under neighbor */
! 416: return 0;
! 417:
! 418: } /* GenId mismatch: replace neighbor */
! 419:
! 420: } /* GenId received */
! 421:
! 422: /*
! 423: Update existing neighbor
! 424: */
! 425:
! 426: pim_neighbor_update(neigh,
! 427: hello_options,
! 428: hello_option_holdtime,
! 429: hello_option_dr_priority,
! 430: hello_option_addr_list);
! 431: /* actual addr list is saved under neighbor */
! 432: return 0;
! 433: }
! 434:
! 435: int pim_hello_build_tlv(const char *ifname,
! 436: uint8_t *tlv_buf, int tlv_buf_size,
! 437: uint16_t holdtime,
! 438: uint32_t dr_priority,
! 439: uint32_t generation_id,
! 440: uint16_t propagation_delay,
! 441: uint16_t override_interval,
! 442: int can_disable_join_suppression,
! 443: struct list *ifconnected)
! 444: {
! 445: uint8_t *curr = tlv_buf;
! 446: uint8_t *pastend = tlv_buf + tlv_buf_size;
! 447: uint8_t *tmp;
! 448:
! 449: /*
! 450: * Append options
! 451: */
! 452:
! 453: /* Holdtime */
! 454: curr = pim_tlv_append_uint16(curr,
! 455: pastend,
! 456: PIM_MSG_OPTION_TYPE_HOLDTIME,
! 457: holdtime);
! 458: if (!curr) {
! 459: if (PIM_DEBUG_PIM_HELLO) {
! 460: zlog_debug("%s: could not set PIM hello Holdtime option for interface %s",
! 461: __PRETTY_FUNCTION__, ifname);
! 462: }
! 463: return -1;
! 464: }
! 465:
! 466: /* LAN Prune Delay */
! 467: tmp = pim_tlv_append_2uint16(curr,
! 468: pastend,
! 469: PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY,
! 470: propagation_delay,
! 471: override_interval);
! 472: if (!tmp) {
! 473: if (PIM_DEBUG_PIM_HELLO) {
! 474: zlog_debug("%s: could not set PIM LAN Prune Delay option for interface %s",
! 475: __PRETTY_FUNCTION__, ifname);
! 476: }
! 477: return -1;
! 478: }
! 479: if (can_disable_join_suppression) {
! 480: *((uint8_t*)(curr) + 4) |= 0x80; /* enable T bit */
! 481: }
! 482: curr = tmp;
! 483:
! 484: /* DR Priority */
! 485: curr = pim_tlv_append_uint32(curr,
! 486: pastend,
! 487: PIM_MSG_OPTION_TYPE_DR_PRIORITY,
! 488: dr_priority);
! 489: if (!curr) {
! 490: if (PIM_DEBUG_PIM_HELLO) {
! 491: zlog_debug("%s: could not set PIM hello DR Priority option for interface %s",
! 492: __PRETTY_FUNCTION__, ifname);
! 493: }
! 494: return -2;
! 495: }
! 496:
! 497: /* Generation ID */
! 498: curr = pim_tlv_append_uint32(curr,
! 499: pastend,
! 500: PIM_MSG_OPTION_TYPE_GENERATION_ID,
! 501: generation_id);
! 502: if (!curr) {
! 503: if (PIM_DEBUG_PIM_HELLO) {
! 504: zlog_debug("%s: could not set PIM hello Generation ID option for interface %s",
! 505: __PRETTY_FUNCTION__, ifname);
! 506: }
! 507: return -3;
! 508: }
! 509:
! 510: /* Secondary Address List */
! 511: if (ifconnected) {
! 512: curr = pim_tlv_append_addrlist_ucast(curr,
! 513: pastend,
! 514: ifconnected);
! 515: if (!curr) {
! 516: if (PIM_DEBUG_PIM_HELLO) {
! 517: zlog_debug("%s: could not set PIM hello Secondary Address List option for interface %s",
! 518: __PRETTY_FUNCTION__, ifname);
! 519: }
! 520: return -4;
! 521: }
! 522: }
! 523:
! 524: return curr - tlv_buf;
! 525: }
! 526:
! 527: /*
! 528: RFC 4601: 4.3.1. Sending Hello Messages
! 529:
! 530: Thus, if a router needs to send a Join/Prune or Assert message on an
! 531: interface on which it has not yet sent a Hello message with the
! 532: currently configured IP address, then it MUST immediately send the
! 533: relevant Hello message without waiting for the Hello Timer to
! 534: expire, followed by the Join/Prune or Assert message.
! 535: */
! 536: void pim_hello_require(struct interface *ifp)
! 537: {
! 538: struct pim_interface *pim_ifp;
! 539:
! 540: zassert(ifp);
! 541:
! 542: pim_ifp = ifp->info;
! 543:
! 544: zassert(pim_ifp);
! 545:
! 546: if (pim_ifp->pim_ifstat_hello_sent)
! 547: return;
! 548:
! 549: pim_hello_restart_now(ifp); /* Send hello and restart timer */
! 550: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>