File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / pimd / pim_static.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 (8 years, 7 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    1: /*
    2:   PIM for Quagga: add the ability to configure multicast static routes
    3:   Copyright (C) 2014  Nathan Bahr, ATCorp
    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 "pim_static.h"
   26: #include "pim_time.h"
   27: #include "pim_str.h"
   28: #include "pimd.h"
   29: #include "pim_iface.h"
   30: #include "log.h"
   31: #include "memory.h"
   32: #include "linklist.h"
   33: 
   34: void pim_static_route_free(struct static_route *s_route)
   35: {
   36:   XFREE(MTYPE_PIM_STATIC_ROUTE, s_route);
   37: }
   38: 
   39: static struct static_route * static_route_alloc()
   40: {
   41:    struct static_route *s_route;
   42: 
   43:    s_route = XCALLOC(MTYPE_PIM_STATIC_ROUTE, sizeof(*s_route));
   44:    if (!s_route) {
   45:      zlog_err("PIM XCALLOC(%zu) failure", sizeof(*s_route));
   46:      return 0;
   47:    }
   48:    return s_route;
   49: }
   50: 
   51: static struct static_route *static_route_new(unsigned int   iif,
   52:                                              unsigned int   oif,
   53:                                              struct in_addr group,
   54:                                              struct in_addr source)
   55: {
   56:   struct static_route * s_route;
   57:   s_route = static_route_alloc();
   58:   if (!s_route) {
   59:      return 0;
   60:   }
   61: 
   62:   s_route->group             = group;
   63:   s_route->source            = source;
   64:   s_route->iif               = iif;
   65:   s_route->oif_ttls[oif]     = 1;
   66:   s_route->oif_count         = 1;
   67:   s_route->mc.mfcc_origin    = source;
   68:   s_route->mc.mfcc_mcastgrp  = group;
   69:   s_route->mc.mfcc_parent    = iif;
   70:   s_route->mc.mfcc_ttls[oif] = 1;
   71:   s_route->creation[oif] = pim_time_monotonic_sec();
   72: 
   73:   return s_route;
   74: }
   75: 
   76: 
   77: int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source)
   78: {
   79:    struct listnode *node = 0;
   80:    struct static_route *s_route = 0;
   81:    struct static_route *original_s_route = 0;
   82:    struct pim_interface *pim_iif = iif ? iif->info : 0;
   83:    struct pim_interface *pim_oif = oif ? oif->info : 0;
   84:    unsigned int iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
   85:    unsigned int oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;
   86: 
   87:    if (!iif_index || !oif_index) {
   88:       zlog_warn("%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)",
   89:                __FILE__, __PRETTY_FUNCTION__,
   90:                iif_index,
   91:                oif_index);
   92:       return -2;
   93:    }
   94: 
   95: #ifdef PIM_ENFORCE_LOOPFREE_MFC
   96:    if (iif_index == oif_index) {
   97:       /* looped MFC entry */
   98:       zlog_warn("%s %s: Unable to add static route: Looped MFC entry(iif=%d,oif=%d)",
   99:                __FILE__, __PRETTY_FUNCTION__,
  100:                iif_index,
  101:                oif_index);
  102:       return -4;
  103:    }
  104: #endif
  105: 
  106:    for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) {
  107:       if (s_route->group.s_addr == group.s_addr &&
  108:           s_route->source.s_addr == source.s_addr) {
  109:          if (s_route->iif == iif_index &&
  110:              s_route->oif_ttls[oif_index]) {
  111:             char gifaddr_str[100];
  112:             char sifaddr_str[100];
  113:             pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
  114:             pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
  115:             zlog_warn("%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)",
  116:                      __FILE__, __PRETTY_FUNCTION__,
  117:                      iif_index,
  118:                      oif_index,
  119:                      gifaddr_str,
  120:                      sifaddr_str);
  121:             return -3;
  122:          }
  123: 
  124:          /* Ok, from here on out we will be making changes to the s_route structure, but if
  125:           * for some reason we fail to commit these changes to the kernel, we want to be able
  126:           * restore the state of the list. So copy the node data and if need be, we can copy
  127:           * back if it fails.
  128:           */
  129:          original_s_route = static_route_alloc();
  130:          if (!original_s_route) {
  131:             return -5;
  132:          }
  133:          memcpy(original_s_route, s_route, sizeof(struct static_route));
  134: 
  135:          /* Route exists and has the same input interface, but adding a new output interface */
  136:          if (s_route->iif == iif_index) {
  137:             s_route->oif_ttls[oif_index] = 1;
  138:             s_route->mc.mfcc_ttls[oif_index] = 1;
  139:             s_route->creation[oif_index] = pim_time_monotonic_sec();
  140:             ++s_route->oif_count;
  141:          } else {
  142:             /* input interface changed */
  143:             s_route->iif = iif_index;
  144:             s_route->mc.mfcc_parent = iif_index;
  145: 
  146: #ifdef PIM_ENFORCE_LOOPFREE_MFC
  147:             /* check to make sure the new input was not an old output */
  148:             if (s_route->oif_ttls[iif_index]) {
  149:                s_route->oif_ttls[iif_index] = 0;
  150:                s_route->creation[iif_index] = 0;
  151:                s_route->mc.mfcc_ttls[iif_index] = 0;
  152:                --s_route->oif_count;
  153:             }
  154: #endif
  155: 
  156:             /* now add the new output, if it is new */
  157:             if (!s_route->oif_ttls[oif_index]) {
  158:                s_route->oif_ttls[oif_index] = 1;
  159:                s_route->creation[oif_index] = pim_time_monotonic_sec();
  160:                s_route->mc.mfcc_ttls[oif_index] = 1;
  161:                ++s_route->oif_count;
  162:             }
  163:          }
  164: 
  165:          break;
  166:       }
  167:    }
  168: 
  169:    /* If node is null then we reached the end of the list without finding a match */
  170:    if (!node) {
  171:       s_route = static_route_new(iif_index, oif_index, group, source);
  172:       listnode_add(qpim_static_route_list, s_route);
  173:    }
  174: 
  175:    if (pim_mroute_add(&(s_route->mc)))
  176:    {
  177:       char gifaddr_str[100];
  178:       char sifaddr_str[100];
  179:       pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
  180:       pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
  181:       zlog_warn("%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)",
  182:                __FILE__, __PRETTY_FUNCTION__,
  183:                iif_index,
  184:                oif_index,
  185:                gifaddr_str,
  186:                sifaddr_str);
  187: 
  188:       /* Need to put s_route back to the way it was */
  189:       if (original_s_route) {
  190:          memcpy(s_route, original_s_route, sizeof(struct static_route));
  191:       } else {
  192:          /* we never stored off a copy, so it must have been a fresh new route */
  193:          listnode_delete(qpim_static_route_list, s_route);
  194:          pim_static_route_free(s_route);
  195:       }
  196: 
  197:       return -1;
  198:    }
  199: 
  200:    /* Make sure we free the memory for the route copy if used */
  201:    if (original_s_route) {
  202:       pim_static_route_free(original_s_route);
  203:    }
  204: 
  205:    if (PIM_DEBUG_STATIC) {
  206:      char gifaddr_str[100];
  207:      char sifaddr_str[100];
  208:      pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
  209:      pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
  210:      zlog_debug("%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)",
  211:            __PRETTY_FUNCTION__,
  212:            iif_index,
  213:            oif_index,
  214:            gifaddr_str,
  215:            sifaddr_str);
  216:    }
  217: 
  218:    return 0;
  219: }
  220: 
  221: int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source)
  222: {
  223:    struct listnode *node = 0;
  224:    struct listnode *nextnode = 0;
  225:    struct static_route *s_route = 0;
  226:    struct pim_interface *pim_iif = iif ? iif->info : 0;
  227:    struct pim_interface *pim_oif = oif ? oif->info : 0;
  228:    unsigned int iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
  229:    unsigned int oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;
  230: 
  231:    if (!iif_index || !oif_index) {
  232:       zlog_warn("%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)",
  233:                __FILE__, __PRETTY_FUNCTION__,
  234:                iif_index,
  235:                oif_index);
  236:       return -2;
  237:    }
  238: 
  239:    for (ALL_LIST_ELEMENTS(qpim_static_route_list, node, nextnode, s_route)) {
  240:       if (s_route->iif == iif_index &&
  241:           s_route->group.s_addr == group.s_addr &&
  242:           s_route->source.s_addr == source.s_addr &&
  243:           s_route->oif_ttls[oif_index]) {
  244:          s_route->oif_ttls[oif_index] = 0;
  245:          s_route->mc.mfcc_ttls[oif_index] = 0;
  246:          --s_route->oif_count;
  247: 
  248:          /* If there are no more outputs then delete the whole route, otherwise set the route with the new outputs */
  249:          if (s_route->oif_count <= 0 ? pim_mroute_del(&s_route->mc) : pim_mroute_add(&s_route->mc)) {
  250:             char gifaddr_str[100];
  251:             char sifaddr_str[100];
  252:             pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
  253:             pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
  254:             zlog_warn("%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)",
  255:                      __FILE__, __PRETTY_FUNCTION__,
  256:                      iif_index,
  257:                      oif_index,
  258:                      gifaddr_str,
  259:                      sifaddr_str);
  260: 
  261:             s_route->oif_ttls[oif_index] = 1;
  262:             s_route->mc.mfcc_ttls[oif_index] = 1;
  263:             ++s_route->oif_count;
  264: 
  265:             return -1;
  266:          }
  267: 
  268:          s_route->creation[oif_index] = 0;
  269: 
  270:          if (s_route->oif_count <= 0) {
  271:             listnode_delete(qpim_static_route_list, s_route);
  272:             pim_static_route_free(s_route);
  273:          }
  274: 
  275:          if (PIM_DEBUG_STATIC) {
  276:            char gifaddr_str[100];
  277:            char sifaddr_str[100];
  278:            pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
  279:            pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
  280:            zlog_debug("%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)",
  281:                  __PRETTY_FUNCTION__,
  282:                  iif_index,
  283:                  oif_index,
  284:                  gifaddr_str,
  285:                  sifaddr_str);
  286:          }
  287: 
  288:          break;
  289:       }
  290:    }
  291: 
  292:    if (!node) {
  293:       char gifaddr_str[100];
  294:       char sifaddr_str[100];
  295:       pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
  296:       pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
  297:       zlog_warn("%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)",
  298:                __FILE__, __PRETTY_FUNCTION__,
  299:                iif_index,
  300:                oif_index,
  301:                gifaddr_str,
  302:                sifaddr_str);
  303:       return -3;
  304:    }
  305: 
  306:    return 0;
  307: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>