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>