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