Annotation of embedaddon/quagga/pimd/pim_static.c, revision 1.1

1.1     ! misho       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>