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