]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_static.c
*: reindent
[mirror_frr.git] / pimd / pim_static.c
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
21 #include <zebra.h>
22
23 #include "vty.h"
24 #include "if.h"
25 #include "log.h"
26 #include "memory.h"
27 #include "linklist.h"
28
29 #include "pimd.h"
30 #include "pim_oil.h"
31 #include "pim_static.h"
32 #include "pim_time.h"
33 #include "pim_str.h"
34 #include "pim_iface.h"
35
36 void pim_static_route_free(struct static_route *s_route)
37 {
38 XFREE(MTYPE_PIM_STATIC_ROUTE, s_route);
39 }
40
41 static struct static_route *static_route_alloc()
42 {
43 struct static_route *s_route;
44
45 s_route = XCALLOC(MTYPE_PIM_STATIC_ROUTE, sizeof(*s_route));
46 if (!s_route) {
47 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*s_route));
48 return 0;
49 }
50 return s_route;
51 }
52
53 static struct static_route *static_route_new(unsigned int iif, unsigned int oif,
54 struct in_addr group,
55 struct in_addr source)
56 {
57 struct static_route *s_route;
58 s_route = static_route_alloc();
59 if (!s_route) {
60 return 0;
61 }
62
63 s_route->group = group;
64 s_route->source = source;
65 s_route->iif = iif;
66 s_route->oif_ttls[oif] = 1;
67 s_route->c_oil.oil_ref_count = 1;
68 s_route->c_oil.oil.mfcc_origin = source;
69 s_route->c_oil.oil.mfcc_mcastgrp = group;
70 s_route->c_oil.oil.mfcc_parent = iif;
71 s_route->c_oil.oil.mfcc_ttls[oif] = 1;
72 s_route->c_oil.oif_creation[oif] = pim_time_monotonic_sec();
73
74 return s_route;
75 }
76
77
78 int pim_static_add(struct interface *iif, struct interface *oif,
79 struct in_addr group, struct in_addr source)
80 {
81 struct listnode *node = NULL;
82 struct static_route *s_route = NULL;
83 struct static_route *original_s_route = NULL;
84 struct pim_interface *pim_iif = iif ? iif->info : NULL;
85 struct pim_interface *pim_oif = oif ? oif->info : NULL;
86 ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
87 ifindex_t oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;
88
89 if (!iif_index || !oif_index) {
90 zlog_warn(
91 "%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)",
92 __FILE__, __PRETTY_FUNCTION__, iif_index, oif_index);
93 return -2;
94 }
95
96 #ifdef PIM_ENFORCE_LOOPFREE_MFC
97 if (iif_index == oif_index) {
98 /* looped MFC entry */
99 zlog_warn(
100 "%s %s: Unable to add static route: Looped MFC entry(iif=%d,oif=%d)",
101 __FILE__, __PRETTY_FUNCTION__, iif_index, 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[INET_ADDRSTRLEN];
112 char sifaddr_str[INET_ADDRSTRLEN];
113 pim_inet4_dump("<ifaddr?>", group, gifaddr_str,
114 sizeof(gifaddr_str));
115 pim_inet4_dump("<ifaddr?>", source, sifaddr_str,
116 sizeof(sifaddr_str));
117 zlog_warn(
118 "%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)",
119 __FILE__, __PRETTY_FUNCTION__,
120 iif_index, oif_index, gifaddr_str,
121 sifaddr_str);
122 return -3;
123 }
124
125 /* Ok, from here on out we will be making changes to the
126 * s_route structure, but if
127 * for some reason we fail to commit these changes to
128 * the kernel, we want to be able
129 * restore the state of the list. So copy the node data
130 * and if need be, we can copy
131 * back if it fails.
132 */
133 original_s_route = static_route_alloc();
134 if (!original_s_route) {
135 return -5;
136 }
137 memcpy(original_s_route, s_route,
138 sizeof(struct static_route));
139
140 /* Route exists and has the same input interface, but
141 * adding a new output interface */
142 if (s_route->iif == iif_index) {
143 s_route->oif_ttls[oif_index] = 1;
144 s_route->c_oil.oil.mfcc_ttls[oif_index] = 1;
145 s_route->c_oil.oif_creation[oif_index] =
146 pim_time_monotonic_sec();
147 ++s_route->c_oil.oil_ref_count;
148 } else {
149 /* input interface changed */
150 s_route->iif = iif_index;
151 s_route->c_oil.oil.mfcc_parent = iif_index;
152
153 #ifdef PIM_ENFORCE_LOOPFREE_MFC
154 /* check to make sure the new input was not an
155 * old output */
156 if (s_route->oif_ttls[iif_index]) {
157 s_route->oif_ttls[iif_index] = 0;
158 s_route->c_oil.oif_creation[iif_index] =
159 0;
160 s_route->c_oil.oil
161 .mfcc_ttls[iif_index] = 0;
162 --s_route->c_oil.oil_ref_count;
163 }
164 #endif
165
166 /* now add the new output, if it is new */
167 if (!s_route->oif_ttls[oif_index]) {
168 s_route->oif_ttls[oif_index] = 1;
169 s_route->c_oil.oif_creation[oif_index] =
170 pim_time_monotonic_sec();
171 s_route->c_oil.oil
172 .mfcc_ttls[oif_index] = 1;
173 ++s_route->c_oil.oil_ref_count;
174 }
175 }
176
177 break;
178 }
179 }
180
181 /* If node is null then we reached the end of the list without finding a
182 * match */
183 if (!node) {
184 s_route = static_route_new(iif_index, oif_index, group, source);
185 listnode_add(qpim_static_route_list, s_route);
186 }
187
188 if (pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__)) {
189 char gifaddr_str[INET_ADDRSTRLEN];
190 char sifaddr_str[INET_ADDRSTRLEN];
191 pim_inet4_dump("<ifaddr?>", group, gifaddr_str,
192 sizeof(gifaddr_str));
193 pim_inet4_dump("<ifaddr?>", source, sifaddr_str,
194 sizeof(sifaddr_str));
195 zlog_warn(
196 "%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)",
197 __FILE__, __PRETTY_FUNCTION__, iif_index, oif_index,
198 gifaddr_str, sifaddr_str);
199
200 /* Need to put s_route back to the way it was */
201 if (original_s_route) {
202 memcpy(s_route, original_s_route,
203 sizeof(struct static_route));
204 } else {
205 /* we never stored off a copy, so it must have been a
206 * fresh new route */
207 listnode_delete(qpim_static_route_list, s_route);
208 pim_static_route_free(s_route);
209 }
210
211 if (original_s_route) {
212 pim_static_route_free(original_s_route);
213 }
214
215 return -1;
216 }
217
218 /* Make sure we free the memory for the route copy if used */
219 if (original_s_route) {
220 pim_static_route_free(original_s_route);
221 }
222
223 if (PIM_DEBUG_STATIC) {
224 char gifaddr_str[INET_ADDRSTRLEN];
225 char sifaddr_str[INET_ADDRSTRLEN];
226 pim_inet4_dump("<ifaddr?>", group, gifaddr_str,
227 sizeof(gifaddr_str));
228 pim_inet4_dump("<ifaddr?>", source, sifaddr_str,
229 sizeof(sifaddr_str));
230 zlog_debug(
231 "%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)",
232 __PRETTY_FUNCTION__, iif_index, oif_index, gifaddr_str,
233 sifaddr_str);
234 }
235
236 return 0;
237 }
238
239 int pim_static_del(struct interface *iif, struct interface *oif,
240 struct in_addr group, struct in_addr source)
241 {
242 struct listnode *node = NULL;
243 struct listnode *nextnode = NULL;
244 struct static_route *s_route = NULL;
245 struct pim_interface *pim_iif = iif ? iif->info : 0;
246 struct pim_interface *pim_oif = oif ? oif->info : 0;
247 ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
248 ifindex_t oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;
249
250 if (!iif_index || !oif_index) {
251 zlog_warn(
252 "%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)",
253 __FILE__, __PRETTY_FUNCTION__, iif_index, oif_index);
254 return -2;
255 }
256
257 for (ALL_LIST_ELEMENTS(qpim_static_route_list, node, nextnode,
258 s_route)) {
259 if (s_route->iif == iif_index
260 && s_route->group.s_addr == group.s_addr
261 && s_route->source.s_addr == source.s_addr
262 && s_route->oif_ttls[oif_index]) {
263 s_route->oif_ttls[oif_index] = 0;
264 s_route->c_oil.oil.mfcc_ttls[oif_index] = 0;
265 --s_route->c_oil.oil_ref_count;
266
267 /* If there are no more outputs then delete the whole
268 * route, otherwise set the route with the new outputs
269 */
270 if (s_route->c_oil.oil_ref_count <= 0
271 ? pim_mroute_del(&s_route->c_oil,
272 __PRETTY_FUNCTION__)
273 : pim_mroute_add(&s_route->c_oil,
274 __PRETTY_FUNCTION__)) {
275 char gifaddr_str[INET_ADDRSTRLEN];
276 char sifaddr_str[INET_ADDRSTRLEN];
277 pim_inet4_dump("<ifaddr?>", group, gifaddr_str,
278 sizeof(gifaddr_str));
279 pim_inet4_dump("<ifaddr?>", source, sifaddr_str,
280 sizeof(sifaddr_str));
281 zlog_warn(
282 "%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)",
283 __FILE__, __PRETTY_FUNCTION__,
284 iif_index, oif_index, gifaddr_str,
285 sifaddr_str);
286
287 s_route->oif_ttls[oif_index] = 1;
288 s_route->c_oil.oil.mfcc_ttls[oif_index] = 1;
289 ++s_route->c_oil.oil_ref_count;
290
291 return -1;
292 }
293
294 s_route->c_oil.oif_creation[oif_index] = 0;
295
296 if (s_route->c_oil.oil_ref_count <= 0) {
297 listnode_delete(qpim_static_route_list,
298 s_route);
299 pim_static_route_free(s_route);
300 }
301
302 if (PIM_DEBUG_STATIC) {
303 char gifaddr_str[INET_ADDRSTRLEN];
304 char sifaddr_str[INET_ADDRSTRLEN];
305 pim_inet4_dump("<ifaddr?>", group, gifaddr_str,
306 sizeof(gifaddr_str));
307 pim_inet4_dump("<ifaddr?>", source, sifaddr_str,
308 sizeof(sifaddr_str));
309 zlog_debug(
310 "%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)",
311 __PRETTY_FUNCTION__, iif_index,
312 oif_index, gifaddr_str, sifaddr_str);
313 }
314
315 break;
316 }
317 }
318
319 if (!node) {
320 char gifaddr_str[INET_ADDRSTRLEN];
321 char sifaddr_str[INET_ADDRSTRLEN];
322 pim_inet4_dump("<ifaddr?>", group, gifaddr_str,
323 sizeof(gifaddr_str));
324 pim_inet4_dump("<ifaddr?>", source, sifaddr_str,
325 sizeof(sifaddr_str));
326 zlog_warn(
327 "%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)",
328 __FILE__, __PRETTY_FUNCTION__, iif_index, oif_index,
329 gifaddr_str, sifaddr_str);
330 return -3;
331 }
332
333 return 0;
334 }
335
336 int pim_static_write_mroute(struct vty *vty, struct interface *ifp)
337 {
338 struct pim_interface *pim_ifp = ifp->info;
339 struct listnode *node;
340 struct static_route *sroute;
341 int count = 0;
342 char sbuf[INET_ADDRSTRLEN];
343 char gbuf[INET_ADDRSTRLEN];
344
345 if (!pim_ifp)
346 return 0;
347
348 for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, sroute)) {
349 pim_inet4_dump("<ifaddr?>", sroute->group, gbuf, sizeof(gbuf));
350 pim_inet4_dump("<ifaddr?>", sroute->source, sbuf, sizeof(sbuf));
351 if (sroute->iif == pim_ifp->mroute_vif_index) {
352 int i;
353 for (i = 0; i < MAXVIFS; i++)
354 if (sroute->oif_ttls[i]) {
355 struct interface *oifp =
356 pim_if_find_by_vif_index(i);
357 if (sroute->source.s_addr == 0)
358 vty_out(vty,
359 " ip mroute %s %s%s",
360 oifp->name, gbuf,
361 VTY_NEWLINE);
362 else
363 vty_out(vty,
364 " ip mroute %s %s %s%s",
365 oifp->name, gbuf, sbuf,
366 VTY_NEWLINE);
367 count++;
368 }
369 }
370 }
371
372 return count;
373 }