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>