2   PIM for Quagga: add the ability to configure multicast static routes
 
   3   Copyright (C) 2014  Nathan Bahr, ATCorp
 
   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.
 
  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.
 
  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,
 
  20   $QuaggaId: $Format:%an, %ai, %h$ $
 
  27 #include "pim_static.h"
 
  31 #include "pim_iface.h"
 
  36 void pim_static_route_free(struct static_route *s_route)
 
  38   XFREE(MTYPE_PIM_STATIC_ROUTE, s_route);
 
  41 static struct static_route * static_route_alloc()
 
  43    struct static_route *s_route;
 
  45    s_route = XCALLOC(MTYPE_PIM_STATIC_ROUTE, sizeof(*s_route));
 
  47      zlog_err("PIM XCALLOC(%zu) failure", sizeof(*s_route));
 
  53 static struct static_route *static_route_new(unsigned int   iif,
 
  56                                              struct in_addr source)
 
  58   struct static_route * s_route;
 
  59   s_route = static_route_alloc();
 
  64   s_route->group             = group;
 
  65   s_route->source            = source;
 
  67   s_route->oif_ttls[oif]     = 1;
 
  68   s_route->oif_count         = 1;
 
  69   s_route->mc.mfcc_origin    = source;
 
  70   s_route->mc.mfcc_mcastgrp  = group;
 
  71   s_route->mc.mfcc_parent    = iif;
 
  72   s_route->mc.mfcc_ttls[oif] = 1;
 
  73   s_route->creation[oif] = pim_time_monotonic_sec();
 
  79 int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source)
 
  81    struct listnode *node = 0;
 
  82    struct static_route *s_route = 0;
 
  83    struct static_route *original_s_route = 0;
 
  84    struct pim_interface *pim_iif = iif ? iif->info : 0;
 
  85    struct pim_interface *pim_oif = oif ? oif->info : 0;
 
  86    unsigned int iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
 
  87    unsigned int oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;
 
  89    if (!iif_index || !oif_index) {
 
  90       zlog_warn("%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)",
 
  91                __FILE__, __PRETTY_FUNCTION__,
 
  97 #ifdef PIM_ENFORCE_LOOPFREE_MFC
 
  98    if (iif_index == oif_index) {
 
  99       /* looped MFC entry */
 
 100       zlog_warn("%s %s: Unable to add static route: Looped MFC entry(iif=%d,oif=%d)",
 
 101                __FILE__, __PRETTY_FUNCTION__,
 
 108    for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) {
 
 109       if (s_route->group.s_addr == group.s_addr &&
 
 110           s_route->source.s_addr == source.s_addr) {
 
 111          if (s_route->iif == iif_index &&
 
 112              s_route->oif_ttls[oif_index]) {
 
 113             char gifaddr_str[100];
 
 114             char sifaddr_str[100];
 
 115             pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
 
 116             pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
 
 117             zlog_warn("%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)",
 
 118                      __FILE__, __PRETTY_FUNCTION__,
 
 126          /* Ok, from here on out we will be making changes to the s_route structure, but if
 
 127           * for some reason we fail to commit these changes to the kernel, we want to be able
 
 128           * restore the state of the list. So copy the node data and if need be, we can copy
 
 131          original_s_route = static_route_alloc();
 
 132          if (!original_s_route) {
 
 135          memcpy(original_s_route, s_route, sizeof(struct static_route));
 
 137          /* Route exists and has the same input interface, but adding a new output interface */
 
 138          if (s_route->iif == iif_index) {
 
 139             s_route->oif_ttls[oif_index] = 1;
 
 140             s_route->mc.mfcc_ttls[oif_index] = 1;
 
 141             s_route->creation[oif_index] = pim_time_monotonic_sec();
 
 142             ++s_route->oif_count;
 
 144             /* input interface changed */
 
 145             s_route->iif = iif_index;
 
 146             s_route->mc.mfcc_parent = iif_index;
 
 148 #ifdef PIM_ENFORCE_LOOPFREE_MFC
 
 149             /* check to make sure the new input was not an old output */
 
 150             if (s_route->oif_ttls[iif_index]) {
 
 151                s_route->oif_ttls[iif_index] = 0;
 
 152                s_route->creation[iif_index] = 0;
 
 153                s_route->mc.mfcc_ttls[iif_index] = 0;
 
 154                --s_route->oif_count;
 
 158             /* now add the new output, if it is new */
 
 159             if (!s_route->oif_ttls[oif_index]) {
 
 160                s_route->oif_ttls[oif_index] = 1;
 
 161                s_route->creation[oif_index] = pim_time_monotonic_sec();
 
 162                s_route->mc.mfcc_ttls[oif_index] = 1;
 
 163                ++s_route->oif_count;
 
 171    /* If node is null then we reached the end of the list without finding a match */
 
 173       s_route = static_route_new(iif_index, oif_index, group, source);
 
 174       listnode_add(qpim_static_route_list, s_route);
 
 177    if (pim_mroute_add(&(s_route->mc)))
 
 179       char gifaddr_str[100];
 
 180       char sifaddr_str[100];
 
 181       pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
 
 182       pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
 
 183       zlog_warn("%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)",
 
 184                __FILE__, __PRETTY_FUNCTION__,
 
 190       /* Need to put s_route back to the way it was */
 
 191       if (original_s_route) {
 
 192          memcpy(s_route, original_s_route, sizeof(struct static_route));
 
 194          /* we never stored off a copy, so it must have been a fresh new route */
 
 195          listnode_delete(qpim_static_route_list, s_route);
 
 196          pim_static_route_free(s_route);
 
 199       if (original_s_route) {
 
 200          pim_static_route_free(original_s_route);
 
 206    /* Make sure we free the memory for the route copy if used */
 
 207    if (original_s_route) {
 
 208       pim_static_route_free(original_s_route);
 
 211    if (PIM_DEBUG_STATIC) {
 
 212      char gifaddr_str[100];
 
 213      char sifaddr_str[100];
 
 214      pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
 
 215      pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
 
 216      zlog_debug("%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)",
 
 227 int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source)
 
 229    struct listnode *node = 0;
 
 230    struct listnode *nextnode = 0;
 
 231    struct static_route *s_route = 0;
 
 232    struct pim_interface *pim_iif = iif ? iif->info : 0;
 
 233    struct pim_interface *pim_oif = oif ? oif->info : 0;
 
 234    unsigned int iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
 
 235    unsigned int oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;
 
 237    if (!iif_index || !oif_index) {
 
 238       zlog_warn("%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)",
 
 239                __FILE__, __PRETTY_FUNCTION__,
 
 245    for (ALL_LIST_ELEMENTS(qpim_static_route_list, node, nextnode, s_route)) {
 
 246       if (s_route->iif == iif_index &&
 
 247           s_route->group.s_addr == group.s_addr &&
 
 248           s_route->source.s_addr == source.s_addr &&
 
 249           s_route->oif_ttls[oif_index]) {
 
 250          s_route->oif_ttls[oif_index] = 0;
 
 251          s_route->mc.mfcc_ttls[oif_index] = 0;
 
 252          --s_route->oif_count;
 
 254          /* If there are no more outputs then delete the whole route, otherwise set the route with the new outputs */
 
 255          if (s_route->oif_count <= 0 ? pim_mroute_del(&s_route->mc) : pim_mroute_add(&s_route->mc)) {
 
 256             char gifaddr_str[100];
 
 257             char sifaddr_str[100];
 
 258             pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
 
 259             pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
 
 260             zlog_warn("%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)",
 
 261                      __FILE__, __PRETTY_FUNCTION__,
 
 267             s_route->oif_ttls[oif_index] = 1;
 
 268             s_route->mc.mfcc_ttls[oif_index] = 1;
 
 269             ++s_route->oif_count;
 
 274          s_route->creation[oif_index] = 0;
 
 276          if (s_route->oif_count <= 0) {
 
 277             listnode_delete(qpim_static_route_list, s_route);
 
 278             pim_static_route_free(s_route);
 
 281          if (PIM_DEBUG_STATIC) {
 
 282            char gifaddr_str[100];
 
 283            char sifaddr_str[100];
 
 284            pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
 
 285            pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
 
 286            zlog_debug("%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)",
 
 299       char gifaddr_str[100];
 
 300       char sifaddr_str[100];
 
 301       pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
 
 302       pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
 
 303       zlog_warn("%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)",
 
 304                __FILE__, __PRETTY_FUNCTION__,
 
 316 pim_static_write_mroute (struct vty *vty, struct interface *ifp)
 
 318   struct listnode *node;
 
 319   struct static_route *sroute;
 
 324   for (ALL_LIST_ELEMENTS_RO (qpim_static_route_list, node, sroute))
 
 326       pim_inet4_dump ("<ifaddr?>", sroute->group, gbuf, sizeof (gbuf));
 
 327       pim_inet4_dump ("<ifaddr?>", sroute->source, sbuf, sizeof (sbuf));
 
 328       if (sroute->iif == ifp->ifindex)
 
 331           for (i = 0; i < MAXVIFS; i++)
 
 332             if (sroute->oif_ttls[i])
 
 334                 struct interface *oifp = if_lookup_by_index (i);
 
 335                 vty_out (vty, " ip mroute %s %s %s%s", oifp->name, gbuf, sbuf, VTY_NEWLINE);