Annotation of embedaddon/quagga/pimd/pim_zebra.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 "zebra/rib.h"
! 26:
! 27: #include "if.h"
! 28: #include "log.h"
! 29: #include "prefix.h"
! 30: #include "zclient.h"
! 31: #include "stream.h"
! 32: #include "network.h"
! 33:
! 34: #include "pimd.h"
! 35: #include "pim_pim.h"
! 36: #include "pim_zebra.h"
! 37: #include "pim_iface.h"
! 38: #include "pim_str.h"
! 39: #include "pim_oil.h"
! 40: #include "pim_rpf.h"
! 41: #include "pim_time.h"
! 42: #include "pim_join.h"
! 43: #include "pim_zlookup.h"
! 44: #include "pim_ifchannel.h"
! 45:
! 46: #undef PIM_DEBUG_IFADDR_DUMP
! 47: #define PIM_DEBUG_IFADDR_DUMP
! 48:
! 49: static int fib_lookup_if_vif_index(struct in_addr addr);
! 50: static int del_oif(struct channel_oil *channel_oil,
! 51: struct interface *oif,
! 52: uint32_t proto_mask);
! 53:
! 54: #if 0
! 55: static void zclient_broken(struct zclient *zclient)
! 56: {
! 57: struct listnode *ifnode;
! 58: struct interface *ifp;
! 59:
! 60: zlog_warn("%s %s: broken zclient connection",
! 61: __FILE__, __PRETTY_FUNCTION__);
! 62:
! 63: for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
! 64: pim_if_addr_del_all(ifp);
! 65: }
! 66:
! 67: /* upon return, zclient will discard connected addresses */
! 68: }
! 69: #endif
! 70:
! 71: /* Router-id update message from zebra. */
! 72: static int pim_router_id_update_zebra(int command, struct zclient *zclient,
! 73: zebra_size_t length, vrf_id_t vrf_id)
! 74: {
! 75: struct prefix router_id;
! 76:
! 77: zebra_router_id_update_read(zclient->ibuf, &router_id);
! 78:
! 79: return 0;
! 80: }
! 81:
! 82: static int pim_zebra_if_add(int command, struct zclient *zclient,
! 83: zebra_size_t length, vrf_id_t vrf_id)
! 84: {
! 85: struct interface *ifp;
! 86:
! 87: /*
! 88: zebra api adds/dels interfaces using the same call
! 89: interface_add_read below, see comments in lib/zclient.c
! 90: */
! 91: ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
! 92: if (!ifp)
! 93: return 0;
! 94:
! 95: if (PIM_DEBUG_ZEBRA) {
! 96: zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
! 97: __PRETTY_FUNCTION__,
! 98: ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
! 99: ifp->mtu, if_is_operative(ifp));
! 100: }
! 101:
! 102: if (if_is_operative(ifp))
! 103: pim_if_addr_add_all(ifp);
! 104:
! 105: return 0;
! 106: }
! 107:
! 108: static int pim_zebra_if_del(int command, struct zclient *zclient,
! 109: zebra_size_t length, vrf_id_t vrf_id)
! 110: {
! 111: struct interface *ifp;
! 112:
! 113: /*
! 114: zebra api adds/dels interfaces using the same call
! 115: interface_add_read below, see comments in lib/zclient.c
! 116:
! 117: comments in lib/zclient.c seem to indicate that calling
! 118: zebra_interface_add_read is the correct call, but that
! 119: results in an attemted out of bounds read which causes
! 120: pimd to assert. Other clients use zebra_interface_state_read
! 121: and it appears to work just fine.
! 122: */
! 123: ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
! 124: if (!ifp)
! 125: return 0;
! 126:
! 127: if (PIM_DEBUG_ZEBRA) {
! 128: zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
! 129: __PRETTY_FUNCTION__,
! 130: ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
! 131: ifp->mtu, if_is_operative(ifp));
! 132: }
! 133:
! 134: if (!if_is_operative(ifp))
! 135: pim_if_addr_del_all(ifp);
! 136:
! 137: return 0;
! 138: }
! 139:
! 140: static int pim_zebra_if_state_up(int command, struct zclient *zclient,
! 141: zebra_size_t length, vrf_id_t vrf_id)
! 142: {
! 143: struct interface *ifp;
! 144:
! 145: /*
! 146: zebra api notifies interface up/down events by using the same call
! 147: zebra_interface_state_read below, see comments in lib/zclient.c
! 148: */
! 149: ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
! 150: if (!ifp)
! 151: return 0;
! 152:
! 153: if (PIM_DEBUG_ZEBRA) {
! 154: zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
! 155: __PRETTY_FUNCTION__,
! 156: ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
! 157: ifp->mtu, if_is_operative(ifp));
! 158: }
! 159:
! 160: if (if_is_operative(ifp)) {
! 161: /*
! 162: pim_if_addr_add_all() suffices for bringing up both IGMP and PIM
! 163: */
! 164: pim_if_addr_add_all(ifp);
! 165: }
! 166:
! 167: return 0;
! 168: }
! 169:
! 170: static int pim_zebra_if_state_down(int command, struct zclient *zclient,
! 171: zebra_size_t length, vrf_id_t vrf_id)
! 172: {
! 173: struct interface *ifp;
! 174:
! 175: /*
! 176: zebra api notifies interface up/down events by using the same call
! 177: zebra_interface_state_read below, see comments in lib/zclient.c
! 178: */
! 179: ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
! 180: if (!ifp)
! 181: return 0;
! 182:
! 183: if (PIM_DEBUG_ZEBRA) {
! 184: zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
! 185: __PRETTY_FUNCTION__,
! 186: ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
! 187: ifp->mtu, if_is_operative(ifp));
! 188: }
! 189:
! 190: if (!if_is_operative(ifp)) {
! 191: /*
! 192: pim_if_addr_del_all() suffices for shutting down IGMP,
! 193: but not for shutting down PIM
! 194: */
! 195: pim_if_addr_del_all(ifp);
! 196:
! 197: /*
! 198: pim_sock_delete() closes the socket, stops read and timer threads,
! 199: and kills all neighbors.
! 200: */
! 201: if (ifp->info) {
! 202: pim_sock_delete(ifp, "link down");
! 203: }
! 204: }
! 205:
! 206: return 0;
! 207: }
! 208:
! 209: #ifdef PIM_DEBUG_IFADDR_DUMP
! 210: static void dump_if_address(struct interface *ifp)
! 211: {
! 212: struct connected *ifc;
! 213: struct listnode *node;
! 214:
! 215: zlog_debug("%s %s: interface %s addresses:",
! 216: __FILE__, __PRETTY_FUNCTION__,
! 217: ifp->name);
! 218:
! 219: for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
! 220: struct prefix *p = ifc->address;
! 221:
! 222: if (p->family != AF_INET)
! 223: continue;
! 224:
! 225: zlog_debug("%s %s: interface %s address %s %s",
! 226: __FILE__, __PRETTY_FUNCTION__,
! 227: ifp->name,
! 228: inet_ntoa(p->u.prefix4),
! 229: CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
! 230: "secondary" : "primary");
! 231: }
! 232: }
! 233: #endif
! 234:
! 235: static int pim_zebra_if_address_add(int command, struct zclient *zclient,
! 236: zebra_size_t length, vrf_id_t vrf_id)
! 237: {
! 238: struct connected *c;
! 239: struct prefix *p;
! 240:
! 241: /*
! 242: zebra api notifies address adds/dels events by using the same call
! 243: interface_add_read below, see comments in lib/zclient.c
! 244:
! 245: zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
! 246: will add address to interface list by calling
! 247: connected_add_by_prefix()
! 248: */
! 249: c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
! 250: if (!c)
! 251: return 0;
! 252:
! 253: p = c->address;
! 254: if (p->family != AF_INET)
! 255: return 0;
! 256:
! 257: if (PIM_DEBUG_ZEBRA) {
! 258: char buf[BUFSIZ];
! 259: prefix2str(p, buf, BUFSIZ);
! 260: zlog_debug("%s: %s connected IP address %s flags %u %s",
! 261: __PRETTY_FUNCTION__,
! 262: c->ifp->name, buf, c->flags,
! 263: CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
! 264:
! 265: #ifdef PIM_DEBUG_IFADDR_DUMP
! 266: dump_if_address(c->ifp);
! 267: #endif
! 268: }
! 269:
! 270: if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
! 271: /* trying to add primary address */
! 272:
! 273: struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
! 274: if (primary_addr.s_addr != p->u.prefix4.s_addr) {
! 275: if (PIM_DEBUG_ZEBRA) {
! 276: /* but we had a primary address already */
! 277:
! 278: char buf[BUFSIZ];
! 279: char old[100];
! 280:
! 281: prefix2str(p, buf, BUFSIZ);
! 282: pim_inet4_dump("<old?>", primary_addr, old, sizeof(old));
! 283:
! 284: zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
! 285: __PRETTY_FUNCTION__,
! 286: c->ifp->name, old, buf);
! 287: }
! 288: SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
! 289: }
! 290: }
! 291:
! 292: pim_if_addr_add(c);
! 293:
! 294: return 0;
! 295: }
! 296:
! 297: static int pim_zebra_if_address_del(int command, struct zclient *client,
! 298: zebra_size_t length, vrf_id_t vrf_id)
! 299: {
! 300: struct connected *c;
! 301: struct prefix *p;
! 302:
! 303: /*
! 304: zebra api notifies address adds/dels events by using the same call
! 305: interface_add_read below, see comments in lib/zclient.c
! 306:
! 307: zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
! 308: will remove address from interface list by calling
! 309: connected_delete_by_prefix()
! 310: */
! 311: c = zebra_interface_address_read(command, client->ibuf, vrf_id);
! 312: if (!c)
! 313: return 0;
! 314:
! 315: p = c->address;
! 316: if (p->family != AF_INET)
! 317: return 0;
! 318:
! 319: if (PIM_DEBUG_ZEBRA) {
! 320: char buf[BUFSIZ];
! 321: prefix2str(p, buf, BUFSIZ);
! 322: zlog_debug("%s: %s disconnected IP address %s flags %u %s",
! 323: __PRETTY_FUNCTION__,
! 324: c->ifp->name, buf, c->flags,
! 325: CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
! 326:
! 327: #ifdef PIM_DEBUG_IFADDR_DUMP
! 328: dump_if_address(c->ifp);
! 329: #endif
! 330: }
! 331:
! 332: pim_if_addr_del(c, 0);
! 333:
! 334: return 0;
! 335: }
! 336:
! 337: static void scan_upstream_rpf_cache()
! 338: {
! 339: struct listnode *up_node;
! 340: struct listnode *up_nextnode;
! 341: struct pim_upstream *up;
! 342:
! 343: for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
! 344: struct in_addr old_rpf_addr;
! 345: enum pim_rpf_result rpf_result;
! 346:
! 347: rpf_result = pim_rpf_update(up, &old_rpf_addr);
! 348: if (rpf_result == PIM_RPF_FAILURE)
! 349: continue;
! 350:
! 351: if (rpf_result == PIM_RPF_CHANGED) {
! 352:
! 353: if (up->join_state == PIM_UPSTREAM_JOINED) {
! 354:
! 355: /*
! 356: RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
! 357:
! 358: Transitions from Joined State
! 359:
! 360: RPF'(S,G) changes not due to an Assert
! 361:
! 362: The upstream (S,G) state machine remains in Joined
! 363: state. Send Join(S,G) to the new upstream neighbor, which is
! 364: the new value of RPF'(S,G). Send Prune(S,G) to the old
! 365: upstream neighbor, which is the old value of RPF'(S,G). Set
! 366: the Join Timer (JT) to expire after t_periodic seconds.
! 367: */
! 368:
! 369:
! 370: /* send Prune(S,G) to the old upstream neighbor */
! 371: pim_joinprune_send(up->rpf.source_nexthop.interface,
! 372: old_rpf_addr,
! 373: up->source_addr,
! 374: up->group_addr,
! 375: 0 /* prune */);
! 376:
! 377: /* send Join(S,G) to the current upstream neighbor */
! 378: pim_joinprune_send(up->rpf.source_nexthop.interface,
! 379: up->rpf.rpf_addr,
! 380: up->source_addr,
! 381: up->group_addr,
! 382: 1 /* join */);
! 383:
! 384: pim_upstream_join_timer_restart(up);
! 385: } /* up->join_state == PIM_UPSTREAM_JOINED */
! 386:
! 387: /* FIXME can join_desired actually be changed by pim_rpf_update()
! 388: returning PIM_RPF_CHANGED ? */
! 389: pim_upstream_update_join_desired(up);
! 390:
! 391: } /* PIM_RPF_CHANGED */
! 392:
! 393: } /* for (qpim_upstream_list) */
! 394:
! 395: }
! 396:
! 397: void pim_scan_oil()
! 398: {
! 399: struct listnode *node;
! 400: struct listnode *nextnode;
! 401: struct channel_oil *c_oil;
! 402:
! 403: qpim_scan_oil_last = pim_time_monotonic_sec();
! 404: ++qpim_scan_oil_events;
! 405:
! 406: for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) {
! 407: int old_vif_index;
! 408: int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin);
! 409: if (input_iface_vif_index < 1) {
! 410: char source_str[100];
! 411: char group_str[100];
! 412: pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 413: pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 414: zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)",
! 415: __FILE__, __PRETTY_FUNCTION__,
! 416: source_str, group_str);
! 417: continue;
! 418: }
! 419:
! 420: if (input_iface_vif_index == c_oil->oil.mfcc_parent) {
! 421: /* RPF unchanged */
! 422: continue;
! 423: }
! 424:
! 425: if (PIM_DEBUG_ZEBRA) {
! 426: struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
! 427: struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
! 428: char source_str[100];
! 429: char group_str[100];
! 430: pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 431: pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 432: zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
! 433: __FILE__, __PRETTY_FUNCTION__,
! 434: source_str, group_str,
! 435: old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
! 436: new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
! 437: }
! 438:
! 439: /* new iif loops to existing oif ? */
! 440: if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) {
! 441: struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
! 442:
! 443: if (PIM_DEBUG_ZEBRA) {
! 444: char source_str[100];
! 445: char group_str[100];
! 446: pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 447: pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 448: zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
! 449: __FILE__, __PRETTY_FUNCTION__,
! 450: source_str, group_str,
! 451: new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
! 452: }
! 453:
! 454: del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
! 455: }
! 456:
! 457: /* update iif vif_index */
! 458: old_vif_index = c_oil->oil.mfcc_parent;
! 459: c_oil->oil.mfcc_parent = input_iface_vif_index;
! 460:
! 461: /* update kernel multicast forwarding cache (MFC) */
! 462: if (pim_mroute_add(&c_oil->oil)) {
! 463: /* just log warning */
! 464: struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index);
! 465: struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
! 466: char source_str[100];
! 467: char group_str[100];
! 468: pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 469: pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 470: zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
! 471: __FILE__, __PRETTY_FUNCTION__,
! 472: source_str, group_str,
! 473: old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
! 474: new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
! 475: continue;
! 476: }
! 477:
! 478: } /* for (qpim_channel_oil_list) */
! 479: }
! 480:
! 481: static int on_rpf_cache_refresh(struct thread *t)
! 482: {
! 483: zassert(t);
! 484: zassert(qpim_rpf_cache_refresher);
! 485:
! 486: qpim_rpf_cache_refresher = 0;
! 487:
! 488: /* update PIM protocol state */
! 489: scan_upstream_rpf_cache();
! 490:
! 491: /* update kernel multicast forwarding cache (MFC) */
! 492: pim_scan_oil();
! 493:
! 494: qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
! 495: ++qpim_rpf_cache_refresh_events;
! 496:
! 497: return 0;
! 498: }
! 499:
! 500: static void sched_rpf_cache_refresh()
! 501: {
! 502: ++qpim_rpf_cache_refresh_requests;
! 503:
! 504: if (qpim_rpf_cache_refresher) {
! 505: /* Refresh timer is already running */
! 506: return;
! 507: }
! 508:
! 509: /* Start refresh timer */
! 510:
! 511: if (PIM_DEBUG_ZEBRA) {
! 512: zlog_debug("%s: triggering %ld msec timer",
! 513: __PRETTY_FUNCTION__,
! 514: qpim_rpf_cache_refresh_delay_msec);
! 515: }
! 516:
! 517: THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher,
! 518: on_rpf_cache_refresh,
! 519: 0, qpim_rpf_cache_refresh_delay_msec);
! 520: }
! 521:
! 522: static int redist_read_ipv4_route(int command, struct zclient *zclient,
! 523: zebra_size_t length, vrf_id_t vrf_id)
! 524: {
! 525: struct stream *s;
! 526: struct zapi_ipv4 api;
! 527: ifindex_t ifindex;
! 528: struct in_addr nexthop;
! 529: struct prefix_ipv4 p;
! 530: int min_len = 4;
! 531:
! 532: if (length < min_len) {
! 533: zlog_warn("%s %s: short buffer: length=%d min=%d",
! 534: __FILE__, __PRETTY_FUNCTION__,
! 535: length, min_len);
! 536: return -1;
! 537: }
! 538:
! 539: s = zclient->ibuf;
! 540: ifindex = 0;
! 541: nexthop.s_addr = 0;
! 542:
! 543: /* Type, flags, message. */
! 544: api.type = stream_getc(s);
! 545: api.flags = stream_getc(s);
! 546: api.message = stream_getc(s);
! 547:
! 548: /* IPv4 prefix length. */
! 549: memset(&p, 0, sizeof(struct prefix_ipv4));
! 550: p.family = AF_INET;
! 551: p.prefixlen = stream_getc(s);
! 552:
! 553: min_len +=
! 554: PSIZE(p.prefixlen) +
! 555: CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 +
! 556: CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 +
! 557: CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 +
! 558: CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0;
! 559:
! 560: if (PIM_DEBUG_ZEBRA) {
! 561: zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
! 562: __FILE__, __PRETTY_FUNCTION__,
! 563: length, min_len,
! 564: CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
! 565: CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
! 566: CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
! 567: CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
! 568: }
! 569:
! 570: if (length < min_len) {
! 571: zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
! 572: __FILE__, __PRETTY_FUNCTION__,
! 573: length, min_len,
! 574: CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
! 575: CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
! 576: CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
! 577: CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
! 578: return -1;
! 579: }
! 580:
! 581: /* IPv4 prefix. */
! 582: stream_get(&p.prefix, s, PSIZE(p.prefixlen));
! 583:
! 584: /* Nexthop, ifindex, distance, metric. */
! 585: if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
! 586: api.nexthop_num = stream_getc(s);
! 587: nexthop.s_addr = stream_get_ipv4(s);
! 588: }
! 589: if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
! 590: api.ifindex_num = stream_getc(s);
! 591: ifindex = stream_getl(s);
! 592: }
! 593:
! 594: api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ?
! 595: stream_getc(s) :
! 596: 0;
! 597:
! 598: api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ?
! 599: stream_getl(s) :
! 600: 0;
! 601:
! 602: switch (command) {
! 603: case ZEBRA_IPV4_ROUTE_ADD:
! 604: if (PIM_DEBUG_ZEBRA) {
! 605: char buf[2][INET_ADDRSTRLEN];
! 606: zlog_debug("%s: add %s %s/%d "
! 607: "nexthop %s ifindex %d metric%s %u distance%s %u",
! 608: __PRETTY_FUNCTION__,
! 609: zebra_route_string(api.type),
! 610: inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
! 611: p.prefixlen,
! 612: inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
! 613: ifindex,
! 614: CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
! 615: api.metric,
! 616: CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
! 617: api.distance);
! 618: }
! 619: break;
! 620: case ZEBRA_IPV4_ROUTE_DELETE:
! 621: if (PIM_DEBUG_ZEBRA) {
! 622: char buf[2][INET_ADDRSTRLEN];
! 623: zlog_debug("%s: delete %s %s/%d "
! 624: "nexthop %s ifindex %d metric%s %u distance%s %u",
! 625: __PRETTY_FUNCTION__,
! 626: zebra_route_string(api.type),
! 627: inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
! 628: p.prefixlen,
! 629: inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
! 630: ifindex,
! 631: CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
! 632: api.metric,
! 633: CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
! 634: api.distance);
! 635: }
! 636: break;
! 637: default:
! 638: zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
! 639: return -1;
! 640: }
! 641:
! 642: sched_rpf_cache_refresh();
! 643:
! 644: return 0;
! 645: }
! 646:
! 647: static void pim_zebra_connected(struct zclient *zclient)
! 648: {
! 649: zclient_send_requests(zclient, VRF_DEFAULT);
! 650: }
! 651:
! 652: void pim_zebra_init (struct thread_master *master, char *zebra_sock_path)
! 653: {
! 654: int i;
! 655:
! 656: if (zebra_sock_path)
! 657: zclient_serv_path_set(zebra_sock_path);
! 658:
! 659: #ifdef HAVE_TCP_ZEBRA
! 660: zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT);
! 661: #else
! 662: zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
! 663: #endif
! 664:
! 665: /* Socket for receiving updates from Zebra daemon */
! 666: qpim_zclient_update = zclient_new (master);
! 667:
! 668: qpim_zclient_update->zebra_connected = pim_zebra_connected;
! 669: qpim_zclient_update->router_id_update = pim_router_id_update_zebra;
! 670: qpim_zclient_update->interface_add = pim_zebra_if_add;
! 671: qpim_zclient_update->interface_delete = pim_zebra_if_del;
! 672: qpim_zclient_update->interface_up = pim_zebra_if_state_up;
! 673: qpim_zclient_update->interface_down = pim_zebra_if_state_down;
! 674: qpim_zclient_update->interface_address_add = pim_zebra_if_address_add;
! 675: qpim_zclient_update->interface_address_delete = pim_zebra_if_address_del;
! 676: qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route;
! 677: qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route;
! 678:
! 679: zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM);
! 680: if (PIM_DEBUG_PIM_TRACE) {
! 681: zlog_info("zclient_init cleared redistribution request");
! 682: }
! 683:
! 684: zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM);
! 685:
! 686: /* Request all redistribution */
! 687: for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
! 688: if (i == qpim_zclient_update->redist_default)
! 689: continue;
! 690: vrf_bitmap_set(qpim_zclient_update->redist[i], VRF_DEFAULT);
! 691: if (PIM_DEBUG_PIM_TRACE) {
! 692: zlog_debug("%s: requesting redistribution for %s (%i)",
! 693: __PRETTY_FUNCTION__, zebra_route_string(i), i);
! 694: }
! 695: }
! 696:
! 697: /* Request default information */
! 698: vrf_bitmap_set(qpim_zclient_update->default_information, VRF_DEFAULT);
! 699: if (PIM_DEBUG_PIM_TRACE) {
! 700: zlog_info("%s: requesting default information redistribution",
! 701: __PRETTY_FUNCTION__);
! 702:
! 703: zlog_notice("%s: zclient update socket initialized",
! 704: __PRETTY_FUNCTION__);
! 705: }
! 706:
! 707: zassert(!qpim_zclient_lookup);
! 708: qpim_zclient_lookup = zclient_lookup_new();
! 709: zassert(qpim_zclient_lookup);
! 710: }
! 711:
! 712: void igmp_anysource_forward_start(struct igmp_group *group)
! 713: {
! 714: /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
! 715: zassert(group->group_filtermode_isexcl);
! 716: zassert(listcount(group->group_source_list) < 1);
! 717:
! 718: if (PIM_DEBUG_IGMP_TRACE) {
! 719: zlog_debug("%s %s: UNIMPLEMENTED",
! 720: __FILE__, __PRETTY_FUNCTION__);
! 721: }
! 722: }
! 723:
! 724: void igmp_anysource_forward_stop(struct igmp_group *group)
! 725: {
! 726: /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
! 727: zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
! 728:
! 729: if (PIM_DEBUG_IGMP_TRACE) {
! 730: zlog_debug("%s %s: UNIMPLEMENTED",
! 731: __FILE__, __PRETTY_FUNCTION__);
! 732: }
! 733: }
! 734:
! 735: static int fib_lookup_if_vif_index(struct in_addr addr)
! 736: {
! 737: struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
! 738: int num_ifindex;
! 739: int vif_index;
! 740: ifindex_t first_ifindex;
! 741:
! 742: num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
! 743: PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
! 744: PIM_NEXTHOP_LOOKUP_MAX);
! 745: if (num_ifindex < 1) {
! 746: char addr_str[100];
! 747: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 748: zlog_warn("%s %s: could not find nexthop ifindex for address %s",
! 749: __FILE__, __PRETTY_FUNCTION__,
! 750: addr_str);
! 751: return -1;
! 752: }
! 753:
! 754: first_ifindex = nexthop_tab[0].ifindex;
! 755:
! 756: if (num_ifindex > 1) {
! 757: char addr_str[100];
! 758: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 759: zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
! 760: __FILE__, __PRETTY_FUNCTION__,
! 761: num_ifindex, addr_str, first_ifindex);
! 762: /* debug warning only, do not return */
! 763: }
! 764:
! 765: if (PIM_DEBUG_ZEBRA) {
! 766: char addr_str[100];
! 767: pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
! 768: zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
! 769: __FILE__, __PRETTY_FUNCTION__,
! 770: first_ifindex, ifindex2ifname(first_ifindex), addr_str);
! 771: }
! 772:
! 773: vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
! 774:
! 775: if (vif_index < 1) {
! 776: char addr_str[100];
! 777: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 778: zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
! 779: __FILE__, __PRETTY_FUNCTION__,
! 780: vif_index, addr_str);
! 781: return -2;
! 782: }
! 783:
! 784: zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
! 785:
! 786: if (vif_index > qpim_mroute_oif_highest_vif_index) {
! 787: char addr_str[100];
! 788: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 789: zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
! 790: __FILE__, __PRETTY_FUNCTION__,
! 791: vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
! 792:
! 793: zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
! 794: __FILE__, __PRETTY_FUNCTION__,
! 795: ifindex2ifname(vif_index),
! 796: vif_index);
! 797:
! 798: return -3;
! 799: }
! 800:
! 801: return vif_index;
! 802: }
! 803:
! 804: static int add_oif(struct channel_oil *channel_oil,
! 805: struct interface *oif,
! 806: uint32_t proto_mask)
! 807: {
! 808: struct pim_interface *pim_ifp;
! 809: int old_ttl;
! 810:
! 811: zassert(channel_oil);
! 812:
! 813: pim_ifp = oif->info;
! 814:
! 815: if (PIM_DEBUG_MROUTE) {
! 816: char group_str[100];
! 817: char source_str[100];
! 818: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 819: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 820: zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
! 821: __FILE__, __PRETTY_FUNCTION__,
! 822: source_str, group_str,
! 823: proto_mask, oif->name, pim_ifp->mroute_vif_index);
! 824: }
! 825:
! 826: if (pim_ifp->mroute_vif_index < 1) {
! 827: zlog_warn("%s %s: interface %s vif_index=%d < 1",
! 828: __FILE__, __PRETTY_FUNCTION__,
! 829: oif->name, pim_ifp->mroute_vif_index);
! 830: return -1;
! 831: }
! 832:
! 833: #ifdef PIM_ENFORCE_LOOPFREE_MFC
! 834: /*
! 835: Prevent creating MFC entry with OIF=IIF.
! 836:
! 837: This is a protection against implementation mistakes.
! 838:
! 839: PIM protocol implicitely ensures loopfree multicast topology.
! 840:
! 841: IGMP must be protected against adding looped MFC entries created
! 842: by both source and receiver attached to the same interface. See
! 843: TODO T22.
! 844: */
! 845: if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
! 846: char group_str[100];
! 847: char source_str[100];
! 848: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 849: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 850: zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
! 851: __FILE__, __PRETTY_FUNCTION__,
! 852: proto_mask, oif->name, pim_ifp->mroute_vif_index,
! 853: source_str, group_str);
! 854: return -2;
! 855: }
! 856: #endif
! 857:
! 858: zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
! 859: zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
! 860:
! 861: /* Prevent single protocol from subscribing same interface to
! 862: channel (S,G) multiple times */
! 863: if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
! 864: char group_str[100];
! 865: char source_str[100];
! 866: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 867: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 868: zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
! 869: __FILE__, __PRETTY_FUNCTION__,
! 870: proto_mask, oif->name, pim_ifp->mroute_vif_index,
! 871: channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
! 872: source_str, group_str);
! 873: return -3;
! 874: }
! 875:
! 876: /* Allow other protocol to request subscription of same interface to
! 877: channel (S,G) multiple times, by silently ignoring further
! 878: requests */
! 879: if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
! 880:
! 881: /* Check the OIF really exists before returning, and only log
! 882: warning otherwise */
! 883: if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
! 884: char group_str[100];
! 885: char source_str[100];
! 886: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 887: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 888: zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
! 889: __FILE__, __PRETTY_FUNCTION__,
! 890: proto_mask, oif->name, pim_ifp->mroute_vif_index,
! 891: channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
! 892: source_str, group_str);
! 893: }
! 894:
! 895: return 0;
! 896: }
! 897:
! 898: old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
! 899:
! 900: if (old_ttl > 0) {
! 901: char group_str[100];
! 902: char source_str[100];
! 903: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 904: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 905: zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
! 906: __FILE__, __PRETTY_FUNCTION__,
! 907: oif->name, pim_ifp->mroute_vif_index,
! 908: source_str, group_str);
! 909: return -4;
! 910: }
! 911:
! 912: channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
! 913:
! 914: if (pim_mroute_add(&channel_oil->oil)) {
! 915: char group_str[100];
! 916: char source_str[100];
! 917: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 918: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 919: zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
! 920: __FILE__, __PRETTY_FUNCTION__,
! 921: oif->name, pim_ifp->mroute_vif_index,
! 922: source_str, group_str);
! 923:
! 924: channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
! 925: return -5;
! 926: }
! 927:
! 928: channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
! 929: ++channel_oil->oil_size;
! 930: channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
! 931:
! 932: if (PIM_DEBUG_MROUTE) {
! 933: char group_str[100];
! 934: char source_str[100];
! 935: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 936: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 937: zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
! 938: __FILE__, __PRETTY_FUNCTION__,
! 939: source_str, group_str,
! 940: proto_mask, oif->name, pim_ifp->mroute_vif_index);
! 941: }
! 942:
! 943: return 0;
! 944: }
! 945:
! 946: static int del_oif(struct channel_oil *channel_oil,
! 947: struct interface *oif,
! 948: uint32_t proto_mask)
! 949: {
! 950: struct pim_interface *pim_ifp;
! 951: int old_ttl;
! 952:
! 953: zassert(channel_oil);
! 954:
! 955: pim_ifp = oif->info;
! 956:
! 957: zassert(pim_ifp->mroute_vif_index >= 1);
! 958: zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
! 959: zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
! 960:
! 961: if (PIM_DEBUG_MROUTE) {
! 962: char group_str[100];
! 963: char source_str[100];
! 964: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 965: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 966: zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
! 967: __FILE__, __PRETTY_FUNCTION__,
! 968: source_str, group_str,
! 969: proto_mask, oif->name, pim_ifp->mroute_vif_index);
! 970: }
! 971:
! 972: /* Prevent single protocol from unsubscribing same interface from
! 973: channel (S,G) multiple times */
! 974: if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
! 975: char group_str[100];
! 976: char source_str[100];
! 977: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 978: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 979: zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
! 980: __FILE__, __PRETTY_FUNCTION__,
! 981: proto_mask, oif->name, pim_ifp->mroute_vif_index,
! 982: channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
! 983: source_str, group_str);
! 984: return -2;
! 985: }
! 986:
! 987: /* Mark that protocol is no longer interested in this OIF */
! 988: channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
! 989:
! 990: /* Allow multiple protocols to unsubscribe same interface from
! 991: channel (S,G) multiple times, by silently ignoring requests while
! 992: there is at least one protocol interested in the channel */
! 993: if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
! 994:
! 995: /* Check the OIF keeps existing before returning, and only log
! 996: warning otherwise */
! 997: if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
! 998: char group_str[100];
! 999: char source_str[100];
! 1000: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 1001: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 1002: zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
! 1003: __FILE__, __PRETTY_FUNCTION__,
! 1004: proto_mask, oif->name, pim_ifp->mroute_vif_index,
! 1005: channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
! 1006: source_str, group_str);
! 1007: }
! 1008:
! 1009: return 0;
! 1010: }
! 1011:
! 1012: old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
! 1013:
! 1014: if (old_ttl < 1) {
! 1015: char group_str[100];
! 1016: char source_str[100];
! 1017: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 1018: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 1019: zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
! 1020: __FILE__, __PRETTY_FUNCTION__,
! 1021: oif->name, pim_ifp->mroute_vif_index,
! 1022: source_str, group_str);
! 1023: return -3;
! 1024: }
! 1025:
! 1026: channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
! 1027:
! 1028: if (pim_mroute_add(&channel_oil->oil)) {
! 1029: char group_str[100];
! 1030: char source_str[100];
! 1031: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 1032: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 1033: zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
! 1034: __FILE__, __PRETTY_FUNCTION__,
! 1035: oif->name, pim_ifp->mroute_vif_index,
! 1036: source_str, group_str);
! 1037:
! 1038: channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
! 1039: return -4;
! 1040: }
! 1041:
! 1042: --channel_oil->oil_size;
! 1043:
! 1044: if (channel_oil->oil_size < 1) {
! 1045: if (pim_mroute_del(&channel_oil->oil)) {
! 1046: /* just log a warning in case of failure */
! 1047: char group_str[100];
! 1048: char source_str[100];
! 1049: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 1050: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 1051: zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
! 1052: __FILE__, __PRETTY_FUNCTION__,
! 1053: source_str, group_str);
! 1054: }
! 1055: }
! 1056:
! 1057: if (PIM_DEBUG_MROUTE) {
! 1058: char group_str[100];
! 1059: char source_str[100];
! 1060: pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
! 1061: pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
! 1062: zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
! 1063: __FILE__, __PRETTY_FUNCTION__,
! 1064: source_str, group_str,
! 1065: proto_mask, oif->name, pim_ifp->mroute_vif_index);
! 1066: }
! 1067:
! 1068: return 0;
! 1069: }
! 1070:
! 1071: void igmp_source_forward_start(struct igmp_source *source)
! 1072: {
! 1073: struct igmp_group *group;
! 1074: int result;
! 1075:
! 1076: if (PIM_DEBUG_IGMP_TRACE) {
! 1077: char source_str[100];
! 1078: char group_str[100];
! 1079: pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
! 1080: pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
! 1081: zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
! 1082: __PRETTY_FUNCTION__,
! 1083: source_str, group_str,
! 1084: source->source_group->group_igmp_sock->fd,
! 1085: source->source_group->group_igmp_sock->interface->name,
! 1086: IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
! 1087: }
! 1088:
! 1089: /* Prevent IGMP interface from installing multicast route multiple
! 1090: times */
! 1091: if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
! 1092: return;
! 1093: }
! 1094:
! 1095: group = source->source_group;
! 1096:
! 1097: if (!source->source_channel_oil) {
! 1098: struct pim_interface *pim_oif;
! 1099: int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
! 1100: if (input_iface_vif_index < 1) {
! 1101: char source_str[100];
! 1102: pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
! 1103: zlog_warn("%s %s: could not find input interface for source %s",
! 1104: __FILE__, __PRETTY_FUNCTION__,
! 1105: source_str);
! 1106: return;
! 1107: }
! 1108:
! 1109: /*
! 1110: Protect IGMP against adding looped MFC entries created by both
! 1111: source and receiver attached to the same interface. See TODO
! 1112: T22.
! 1113: */
! 1114: pim_oif = source->source_group->group_igmp_sock->interface->info;
! 1115: if (!pim_oif) {
! 1116: zlog_warn("%s: multicast not enabled on oif=%s ?",
! 1117: __PRETTY_FUNCTION__,
! 1118: source->source_group->group_igmp_sock->interface->name);
! 1119: return;
! 1120: }
! 1121: if (pim_oif->mroute_vif_index < 1) {
! 1122: zlog_warn("%s %s: oif=%s vif_index=%d < 1",
! 1123: __FILE__, __PRETTY_FUNCTION__,
! 1124: source->source_group->group_igmp_sock->interface->name,
! 1125: pim_oif->mroute_vif_index);
! 1126: return;
! 1127: }
! 1128: if (input_iface_vif_index == pim_oif->mroute_vif_index) {
! 1129: /* ignore request for looped MFC entry */
! 1130: if (PIM_DEBUG_IGMP_TRACE) {
! 1131: char source_str[100];
! 1132: char group_str[100];
! 1133: pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
! 1134: pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
! 1135: zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
! 1136: __PRETTY_FUNCTION__,
! 1137: source_str, group_str,
! 1138: source->source_group->group_igmp_sock->fd,
! 1139: source->source_group->group_igmp_sock->interface->name,
! 1140: input_iface_vif_index);
! 1141: }
! 1142: return;
! 1143: }
! 1144:
! 1145: source->source_channel_oil = pim_channel_oil_add(group->group_addr,
! 1146: source->source_addr,
! 1147: input_iface_vif_index);
! 1148: if (!source->source_channel_oil) {
! 1149: char group_str[100];
! 1150: char source_str[100];
! 1151: pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
! 1152: pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
! 1153: zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
! 1154: __FILE__, __PRETTY_FUNCTION__,
! 1155: source_str, group_str);
! 1156: return;
! 1157: }
! 1158: }
! 1159:
! 1160: result = add_oif(source->source_channel_oil,
! 1161: group->group_igmp_sock->interface,
! 1162: PIM_OIF_FLAG_PROTO_IGMP);
! 1163: if (result) {
! 1164: zlog_warn("%s: add_oif() failed with return=%d",
! 1165: __func__, result);
! 1166: return;
! 1167: }
! 1168:
! 1169: /*
! 1170: Feed IGMPv3-gathered local membership information into PIM
! 1171: per-interface (S,G) state.
! 1172: */
! 1173: pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
! 1174: source->source_addr, group->group_addr);
! 1175:
! 1176: IGMP_SOURCE_DO_FORWARDING(source->source_flags);
! 1177: }
! 1178:
! 1179: /*
! 1180: igmp_source_forward_stop: stop fowarding, but keep the source
! 1181: igmp_source_delete: stop fowarding, and delete the source
! 1182: */
! 1183: void igmp_source_forward_stop(struct igmp_source *source)
! 1184: {
! 1185: struct igmp_group *group;
! 1186: int result;
! 1187:
! 1188: if (PIM_DEBUG_IGMP_TRACE) {
! 1189: char source_str[100];
! 1190: char group_str[100];
! 1191: pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
! 1192: pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
! 1193: zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
! 1194: __PRETTY_FUNCTION__,
! 1195: source_str, group_str,
! 1196: source->source_group->group_igmp_sock->fd,
! 1197: source->source_group->group_igmp_sock->interface->name,
! 1198: IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
! 1199: }
! 1200:
! 1201: /* Prevent IGMP interface from removing multicast route multiple
! 1202: times */
! 1203: if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
! 1204: return;
! 1205: }
! 1206:
! 1207: group = source->source_group;
! 1208:
! 1209: /*
! 1210: It appears that in certain circumstances that
! 1211: igmp_source_forward_stop is called when IGMP forwarding
! 1212: was not enabled in oif_flags for this outgoing interface.
! 1213: Possibly because of multiple calls. When that happens, we
! 1214: enter the below if statement and this function returns early
! 1215: which in turn triggers the calling function to assert.
! 1216: Making the call to del_oif and ignoring the return code
! 1217: fixes the issue without ill effect, similar to
! 1218: pim_forward_stop below.
! 1219: */
! 1220: result = del_oif(source->source_channel_oil,
! 1221: group->group_igmp_sock->interface,
! 1222: PIM_OIF_FLAG_PROTO_IGMP);
! 1223: if (result) {
! 1224: zlog_warn("%s: del_oif() failed with return=%d",
! 1225: __func__, result);
! 1226: return;
! 1227: }
! 1228:
! 1229: /*
! 1230: Feed IGMPv3-gathered local membership information into PIM
! 1231: per-interface (S,G) state.
! 1232: */
! 1233: pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
! 1234: source->source_addr, group->group_addr);
! 1235:
! 1236: IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
! 1237: }
! 1238:
! 1239: void pim_forward_start(struct pim_ifchannel *ch)
! 1240: {
! 1241: struct pim_upstream *up = ch->upstream;
! 1242:
! 1243: if (PIM_DEBUG_PIM_TRACE) {
! 1244: char source_str[100];
! 1245: char group_str[100];
! 1246: pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
! 1247: pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
! 1248: zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
! 1249: __PRETTY_FUNCTION__,
! 1250: source_str, group_str, ch->interface->name);
! 1251: }
! 1252:
! 1253: if (!up->channel_oil) {
! 1254: int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
! 1255: if (input_iface_vif_index < 1) {
! 1256: char source_str[100];
! 1257: pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
! 1258: zlog_warn("%s %s: could not find input interface for source %s",
! 1259: __FILE__, __PRETTY_FUNCTION__,
! 1260: source_str);
! 1261: return;
! 1262: }
! 1263:
! 1264: up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
! 1265: input_iface_vif_index);
! 1266: if (!up->channel_oil) {
! 1267: char group_str[100];
! 1268: char source_str[100];
! 1269: pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
! 1270: pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
! 1271: zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
! 1272: __FILE__, __PRETTY_FUNCTION__,
! 1273: source_str, group_str);
! 1274: return;
! 1275: }
! 1276: }
! 1277:
! 1278: add_oif(up->channel_oil,
! 1279: ch->interface,
! 1280: PIM_OIF_FLAG_PROTO_PIM);
! 1281: }
! 1282:
! 1283: void pim_forward_stop(struct pim_ifchannel *ch)
! 1284: {
! 1285: struct pim_upstream *up = ch->upstream;
! 1286:
! 1287: if (PIM_DEBUG_PIM_TRACE) {
! 1288: char source_str[100];
! 1289: char group_str[100];
! 1290: pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
! 1291: pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
! 1292: zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
! 1293: __PRETTY_FUNCTION__,
! 1294: source_str, group_str, ch->interface->name);
! 1295: }
! 1296:
! 1297: if (!up->channel_oil) {
! 1298: char source_str[100];
! 1299: char group_str[100];
! 1300: pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
! 1301: pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
! 1302: zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
! 1303: __PRETTY_FUNCTION__,
! 1304: source_str, group_str, ch->interface->name);
! 1305:
! 1306: return;
! 1307: }
! 1308:
! 1309: del_oif(up->channel_oil,
! 1310: ch->interface,
! 1311: PIM_OIF_FLAG_PROTO_PIM);
! 1312: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>