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