Annotation of embedaddon/quagga/pimd/pim_join.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 "prefix.h"
! 27:
! 28: #include "pimd.h"
! 29: #include "pim_str.h"
! 30: #include "pim_tlv.h"
! 31: #include "pim_msg.h"
! 32: #include "pim_pim.h"
! 33: #include "pim_join.h"
! 34: #include "pim_iface.h"
! 35: #include "pim_hello.h"
! 36: #include "pim_ifchannel.h"
! 37:
! 38: static void on_trace(const char *label,
! 39: struct interface *ifp, struct in_addr src)
! 40: {
! 41: if (PIM_DEBUG_PIM_TRACE) {
! 42: char src_str[100];
! 43: pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
! 44: zlog_debug("%s: from %s on %s",
! 45: label, src_str, ifp->name);
! 46: }
! 47: }
! 48:
! 49: static void recv_join(struct interface *ifp,
! 50: struct pim_neighbor *neigh,
! 51: uint16_t holdtime,
! 52: struct in_addr upstream,
! 53: struct in_addr group,
! 54: struct in_addr source,
! 55: uint8_t source_flags)
! 56: {
! 57: if (PIM_DEBUG_PIM_TRACE) {
! 58: char up_str[100];
! 59: char src_str[100];
! 60: char grp_str[100];
! 61: char neigh_str[100];
! 62: pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
! 63: pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
! 64: pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
! 65: pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
! 66: zlog_warn("%s: join (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
! 67: __PRETTY_FUNCTION__,
! 68: src_str, grp_str,
! 69: source_flags & PIM_RPT_BIT_MASK,
! 70: source_flags & PIM_WILDCARD_BIT_MASK,
! 71: up_str, holdtime, neigh_str, ifp->name);
! 72: }
! 73:
! 74: /* Restart join expiry timer */
! 75: pim_ifchannel_join_add(ifp, neigh->source_addr, upstream,
! 76: source, group, source_flags, holdtime);
! 77: }
! 78:
! 79: static void recv_prune(struct interface *ifp,
! 80: struct pim_neighbor *neigh,
! 81: uint16_t holdtime,
! 82: struct in_addr upstream,
! 83: struct in_addr group,
! 84: struct in_addr source,
! 85: uint8_t source_flags)
! 86: {
! 87: if (PIM_DEBUG_PIM_TRACE) {
! 88: char up_str[100];
! 89: char src_str[100];
! 90: char grp_str[100];
! 91: char neigh_str[100];
! 92: pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
! 93: pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
! 94: pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
! 95: pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
! 96: zlog_warn("%s: prune (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
! 97: __PRETTY_FUNCTION__,
! 98: src_str, grp_str,
! 99: source_flags & PIM_RPT_BIT_MASK,
! 100: source_flags & PIM_WILDCARD_BIT_MASK,
! 101: up_str, holdtime, neigh_str, ifp->name);
! 102: }
! 103:
! 104: pim_ifchannel_prune(ifp, upstream, source, group, source_flags, holdtime);
! 105: }
! 106:
! 107: int pim_joinprune_recv(struct interface *ifp,
! 108: struct pim_neighbor *neigh,
! 109: struct in_addr src_addr,
! 110: uint8_t *tlv_buf, int tlv_buf_size)
! 111: {
! 112: struct prefix msg_upstream_addr;
! 113: uint8_t msg_num_groups;
! 114: uint16_t msg_holdtime;
! 115: int addr_offset;
! 116: uint8_t *buf;
! 117: uint8_t *pastend;
! 118: int remain;
! 119: int group;
! 120:
! 121: on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
! 122:
! 123: buf = tlv_buf;
! 124: pastend = tlv_buf + tlv_buf_size;
! 125:
! 126: /*
! 127: Parse ucast addr
! 128: */
! 129: addr_offset = pim_parse_addr_ucast(ifp->name, src_addr,
! 130: &msg_upstream_addr,
! 131: buf, pastend - buf);
! 132: #if 0
! 133: zlog_warn("%s: pim_parse_addr_ucast addr_offset=%d",
! 134: __PRETTY_FUNCTION__,
! 135: addr_offset);
! 136: #endif
! 137: if (addr_offset < 1) {
! 138: char src_str[100];
! 139: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 140: zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
! 141: __PRETTY_FUNCTION__,
! 142: src_str, ifp->name);
! 143: return -1;
! 144: }
! 145: buf += addr_offset;
! 146:
! 147: /*
! 148: Check upstream address family
! 149: */
! 150: if (msg_upstream_addr.family != AF_INET) {
! 151: if (PIM_DEBUG_PIM_TRACE) {
! 152: char src_str[100];
! 153: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 154: zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
! 155: __PRETTY_FUNCTION__,
! 156: msg_upstream_addr.family, src_str, ifp->name);
! 157: }
! 158: return -2;
! 159: }
! 160:
! 161: remain = pastend - buf;
! 162: if (remain < 4) {
! 163: char src_str[100];
! 164: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 165: zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
! 166: __PRETTY_FUNCTION__,
! 167: remain, 4, src_str, ifp->name);
! 168: return -4;
! 169: }
! 170:
! 171: ++buf; /* skip reserved byte */
! 172: msg_num_groups = *(const uint8_t *) buf;
! 173: ++buf;
! 174: msg_holdtime = ntohs(*(const uint16_t *) buf);
! 175: ++buf;
! 176: ++buf;
! 177:
! 178: if (PIM_DEBUG_PIM_TRACE) {
! 179: char src_str[100];
! 180: char upstream_str[100];
! 181: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 182: pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
! 183: upstream_str, sizeof(upstream_str));
! 184: zlog_warn("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
! 185: __PRETTY_FUNCTION__,
! 186: upstream_str, msg_num_groups, msg_holdtime,
! 187: src_str, ifp->name);
! 188: }
! 189:
! 190: /* Scan groups */
! 191: for (group = 0; group < msg_num_groups; ++group) {
! 192: struct prefix msg_group_addr;
! 193: struct prefix msg_source_addr;
! 194: uint8_t msg_source_flags;
! 195: uint16_t msg_num_joined_sources;
! 196: uint16_t msg_num_pruned_sources;
! 197: int source;
! 198:
! 199: addr_offset = pim_parse_addr_group(ifp->name, src_addr,
! 200: &msg_group_addr,
! 201: buf, pastend - buf);
! 202: #if 0
! 203: zlog_warn("%s: pim_parse_addr_group addr_offset=%d",
! 204: __PRETTY_FUNCTION__,
! 205: addr_offset);
! 206: #endif
! 207: if (addr_offset < 1) {
! 208: return -5;
! 209: }
! 210: buf += addr_offset;
! 211:
! 212: remain = pastend - buf;
! 213: if (remain < 4) {
! 214: char src_str[100];
! 215: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 216: zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
! 217: __PRETTY_FUNCTION__,
! 218: remain, 4, src_str, ifp->name);
! 219: return -6;
! 220: }
! 221:
! 222: msg_num_joined_sources = ntohs(*(const uint16_t *) buf);
! 223: buf += 2;
! 224: msg_num_pruned_sources = ntohs(*(const uint16_t *) buf);
! 225: buf += 2;
! 226:
! 227: if (PIM_DEBUG_PIM_TRACE) {
! 228: char src_str[100];
! 229: char upstream_str[100];
! 230: char group_str[100];
! 231: pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
! 232: pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
! 233: upstream_str, sizeof(upstream_str));
! 234: pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4,
! 235: group_str, sizeof(group_str));
! 236: zlog_warn("%s: join/prune upstream=%s group=%s/%d join_src=%d prune_src=%d from %s on %s",
! 237: __PRETTY_FUNCTION__,
! 238: upstream_str, group_str, msg_group_addr.prefixlen,
! 239: msg_num_joined_sources, msg_num_pruned_sources,
! 240: src_str, ifp->name);
! 241: }
! 242:
! 243: /* Scan joined sources */
! 244: for (source = 0; source < msg_num_joined_sources; ++source) {
! 245: addr_offset = pim_parse_addr_source(ifp->name, src_addr,
! 246: &msg_source_addr,
! 247: &msg_source_flags,
! 248: buf, pastend - buf);
! 249: #if 0
! 250: zlog_warn("%s: pim_parse_addr_source addr_offset=%d",
! 251: __PRETTY_FUNCTION__,
! 252: addr_offset);
! 253: #endif
! 254: if (addr_offset < 1) {
! 255: return -7;
! 256: }
! 257:
! 258: buf += addr_offset;
! 259:
! 260: recv_join(ifp, neigh, msg_holdtime,
! 261: msg_upstream_addr.u.prefix4,
! 262: msg_group_addr.u.prefix4,
! 263: msg_source_addr.u.prefix4,
! 264: msg_source_flags);
! 265: }
! 266:
! 267: /* Scan pruned sources */
! 268: for (source = 0; source < msg_num_pruned_sources; ++source) {
! 269: addr_offset = pim_parse_addr_source(ifp->name, src_addr,
! 270: &msg_source_addr,
! 271: &msg_source_flags,
! 272: buf, pastend - buf);
! 273: if (addr_offset < 1) {
! 274: return -8;
! 275: }
! 276:
! 277: buf += addr_offset;
! 278:
! 279: recv_prune(ifp, neigh, msg_holdtime,
! 280: msg_upstream_addr.u.prefix4,
! 281: msg_group_addr.u.prefix4,
! 282: msg_source_addr.u.prefix4,
! 283: msg_source_flags);
! 284: }
! 285:
! 286: } /* scan groups */
! 287:
! 288: return 0;
! 289: }
! 290:
! 291: int pim_joinprune_send(struct interface *ifp,
! 292: struct in_addr upstream_addr,
! 293: struct in_addr source_addr,
! 294: struct in_addr group_addr,
! 295: int send_join)
! 296: {
! 297: struct pim_interface *pim_ifp;
! 298: uint8_t pim_msg[1000];
! 299: const uint8_t *pastend = pim_msg + sizeof(pim_msg);
! 300: uint8_t *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */
! 301: int pim_msg_size;
! 302: int remain;
! 303:
! 304: zassert(ifp);
! 305:
! 306: pim_ifp = ifp->info;
! 307:
! 308: if (!pim_ifp) {
! 309: zlog_warn("%s: multicast not enabled on interface %s",
! 310: __PRETTY_FUNCTION__,
! 311: ifp->name);
! 312: return -1;
! 313: }
! 314:
! 315: if (PIM_DEBUG_PIM_TRACE) {
! 316: char source_str[100];
! 317: char group_str[100];
! 318: char dst_str[100];
! 319: pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
! 320: pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
! 321: pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
! 322: zlog_debug("%s: sending %s(S,G)=(%s,%s) to upstream=%s on interface %s",
! 323: __PRETTY_FUNCTION__,
! 324: send_join ? "Join" : "Prune",
! 325: source_str, group_str, dst_str, ifp->name);
! 326: }
! 327:
! 328: if (PIM_INADDR_IS_ANY(upstream_addr)) {
! 329: if (PIM_DEBUG_PIM_TRACE) {
! 330: char source_str[100];
! 331: char group_str[100];
! 332: char dst_str[100];
! 333: pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
! 334: pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
! 335: pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
! 336: zlog_debug("%s: %s(S,G)=(%s,%s): upstream=%s is myself on interface %s",
! 337: __PRETTY_FUNCTION__,
! 338: send_join ? "Join" : "Prune",
! 339: source_str, group_str, dst_str, ifp->name);
! 340: }
! 341: return 0;
! 342: }
! 343:
! 344: /*
! 345: RFC 4601: 4.3.1. Sending Hello Messages
! 346:
! 347: Thus, if a router needs to send a Join/Prune or Assert message on
! 348: an interface on which it has not yet sent a Hello message with the
! 349: currently configured IP address, then it MUST immediately send the
! 350: relevant Hello message without waiting for the Hello Timer to
! 351: expire, followed by the Join/Prune or Assert message.
! 352: */
! 353: pim_hello_require(ifp);
! 354:
! 355: /*
! 356: Build PIM message
! 357: */
! 358:
! 359: remain = pastend - pim_msg_curr;
! 360: pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
! 361: remain,
! 362: upstream_addr);
! 363: if (!pim_msg_curr) {
! 364: char dst_str[100];
! 365: pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
! 366: zlog_warn("%s: failure encoding destination address %s: space left=%d",
! 367: __PRETTY_FUNCTION__, dst_str, remain);
! 368: return -3;
! 369: }
! 370:
! 371: remain = pastend - pim_msg_curr;
! 372: if (remain < 4) {
! 373: zlog_warn("%s: group will not fit: space left=%d",
! 374: __PRETTY_FUNCTION__, remain);
! 375: return -4;
! 376: }
! 377:
! 378: *pim_msg_curr = 0; /* reserved */
! 379: ++pim_msg_curr;
! 380: *pim_msg_curr = 1; /* number of groups */
! 381: ++pim_msg_curr;
! 382: *((uint16_t *) pim_msg_curr) = htons(PIM_JP_HOLDTIME);
! 383: ++pim_msg_curr;
! 384: ++pim_msg_curr;
! 385:
! 386: remain = pastend - pim_msg_curr;
! 387: pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
! 388: remain,
! 389: group_addr);
! 390: if (!pim_msg_curr) {
! 391: char group_str[100];
! 392: pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
! 393: zlog_warn("%s: failure encoding group address %s: space left=%d",
! 394: __PRETTY_FUNCTION__, group_str, remain);
! 395: return -5;
! 396: }
! 397:
! 398: remain = pastend - pim_msg_curr;
! 399: if (remain < 4) {
! 400: zlog_warn("%s: sources will not fit: space left=%d",
! 401: __PRETTY_FUNCTION__, remain);
! 402: return -6;
! 403: }
! 404:
! 405: /* number of joined sources */
! 406: *((uint16_t *) pim_msg_curr) = htons(send_join ? 1 : 0);
! 407: ++pim_msg_curr;
! 408: ++pim_msg_curr;
! 409:
! 410: /* number of pruned sources */
! 411: *((uint16_t *) pim_msg_curr) = htons(send_join ? 0 : 1);
! 412: ++pim_msg_curr;
! 413: ++pim_msg_curr;
! 414:
! 415: remain = pastend - pim_msg_curr;
! 416: pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr,
! 417: remain,
! 418: source_addr);
! 419: if (!pim_msg_curr) {
! 420: char source_str[100];
! 421: pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
! 422: zlog_warn("%s: failure encoding source address %s: space left=%d",
! 423: __PRETTY_FUNCTION__, source_str, remain);
! 424: return -7;
! 425: }
! 426:
! 427: /* Add PIM header */
! 428:
! 429: pim_msg_size = pim_msg_curr - pim_msg;
! 430:
! 431: pim_msg_build_header(pim_msg, pim_msg_size,
! 432: PIM_MSG_TYPE_JOIN_PRUNE);
! 433:
! 434: if (pim_msg_send(pim_ifp->pim_sock_fd,
! 435: qpim_all_pim_routers_addr,
! 436: pim_msg,
! 437: pim_msg_size,
! 438: ifp->name)) {
! 439: zlog_warn("%s: could not send PIM message on interface %s",
! 440: __PRETTY_FUNCTION__, ifp->name);
! 441: return -8;
! 442: }
! 443:
! 444: return 0;
! 445: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>