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