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