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>