File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / pimd / pim_zebra.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:11 2016 UTC (7 years, 7 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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>