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