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