Line data Source code
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 0 : void pim_static_route_free(struct static_route *s_route)
37 : {
38 0 : XFREE(MTYPE_PIM_STATIC_ROUTE, s_route);
39 0 : }
40 :
41 0 : static struct static_route *static_route_alloc(void)
42 : {
43 0 : return XCALLOC(MTYPE_PIM_STATIC_ROUTE, sizeof(struct static_route));
44 : }
45 :
46 0 : static struct static_route *static_route_new(ifindex_t iif, ifindex_t oif,
47 : pim_addr group,
48 : pim_addr source)
49 : {
50 0 : struct static_route *s_route;
51 0 : s_route = static_route_alloc();
52 :
53 0 : s_route->group = group;
54 0 : s_route->source = source;
55 0 : s_route->iif = iif;
56 0 : s_route->oif_ttls[oif] = 1;
57 0 : s_route->c_oil.oil_ref_count = 1;
58 0 : *oil_origin(&s_route->c_oil) = source;
59 0 : *oil_mcastgrp(&s_route->c_oil) = group;
60 0 : *oil_parent(&s_route->c_oil) = iif;
61 0 : oil_if_set(&s_route->c_oil, oif, 1);
62 0 : s_route->c_oil.oif_creation[oif] = pim_time_monotonic_sec();
63 :
64 0 : return s_route;
65 : }
66 :
67 :
68 0 : int pim_static_add(struct pim_instance *pim, struct interface *iif,
69 : struct interface *oif, pim_addr group, pim_addr source)
70 : {
71 0 : struct listnode *node = NULL;
72 0 : struct static_route *s_route = NULL;
73 0 : struct static_route *original_s_route = NULL;
74 0 : struct pim_interface *pim_iif = iif ? iif->info : NULL;
75 0 : struct pim_interface *pim_oif = oif ? oif->info : NULL;
76 0 : ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
77 0 : ifindex_t oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;
78 :
79 0 : if (!iif_index || !oif_index || iif_index == -1 || oif_index == -1) {
80 0 : 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 0 : return -2;
84 : }
85 :
86 : #ifdef PIM_ENFORCE_LOOPFREE_MFC
87 0 : if (iif_index == oif_index) {
88 : /* looped MFC entry */
89 0 : 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 0 : return -4;
93 : }
94 : #endif
95 0 : if (iif->vrf->vrf_id != oif->vrf->vrf_id) {
96 : return -3;
97 : }
98 :
99 0 : for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
100 0 : if (!pim_addr_cmp(s_route->group, group) &&
101 0 : !pim_addr_cmp(s_route->source, source) &&
102 0 : (s_route->iif == iif_index)) {
103 :
104 0 : if (s_route->oif_ttls[oif_index]) {
105 0 : 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 0 : 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 0 : original_s_route = static_route_alloc();
121 0 : 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 0 : s_route->oif_ttls[oif_index] = 1;
127 0 : oil_if_set(&s_route->c_oil, oif_index, 1);
128 0 : s_route->c_oil.oif_creation[oif_index] =
129 0 : pim_time_monotonic_sec();
130 0 : ++s_route->c_oil.oil_ref_count;
131 0 : break;
132 : }
133 : }
134 :
135 : /* If node is null then we reached the end of the list without finding a
136 : * match */
137 0 : if (!node) {
138 0 : s_route = static_route_new(iif_index, oif_index, group, source);
139 0 : listnode_add(pim->static_routes, s_route);
140 : }
141 :
142 0 : s_route->c_oil.pim = pim;
143 :
144 0 : if (pim_static_mroute_add(&s_route->c_oil, __func__)) {
145 0 : 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 0 : if (original_s_route) {
152 0 : 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 0 : listnode_delete(pim->static_routes, s_route);
158 0 : pim_static_route_free(s_route);
159 : }
160 :
161 0 : if (original_s_route) {
162 0 : pim_static_route_free(original_s_route);
163 : }
164 :
165 0 : return -1;
166 : }
167 :
168 : /* Make sure we free the memory for the route copy if used */
169 0 : if (original_s_route) {
170 0 : pim_static_route_free(original_s_route);
171 : }
172 :
173 0 : if (PIM_DEBUG_STATIC) {
174 0 : 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 0 : int pim_static_del(struct pim_instance *pim, struct interface *iif,
184 : struct interface *oif, pim_addr group, pim_addr source)
185 : {
186 0 : struct listnode *node = NULL;
187 0 : struct listnode *nextnode = NULL;
188 0 : struct static_route *s_route = NULL;
189 0 : struct pim_interface *pim_iif = iif ? iif->info : 0;
190 0 : struct pim_interface *pim_oif = oif ? oif->info : 0;
191 0 : ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
192 0 : ifindex_t oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;
193 :
194 0 : if (!iif_index || !oif_index) {
195 0 : 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 0 : return -2;
199 : }
200 :
201 0 : for (ALL_LIST_ELEMENTS(pim->static_routes, node, nextnode, s_route)) {
202 0 : if (s_route->iif == iif_index
203 0 : && !pim_addr_cmp(s_route->group, group)
204 0 : && !pim_addr_cmp(s_route->source, source)
205 0 : && s_route->oif_ttls[oif_index]) {
206 0 : s_route->oif_ttls[oif_index] = 0;
207 0 : oil_if_set(&s_route->c_oil, oif_index, 0);
208 0 : --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 0 : if (s_route->c_oil.oil_ref_count <= 0
214 0 : ? pim_mroute_del(&s_route->c_oil, __func__)
215 0 : : pim_static_mroute_add(&s_route->c_oil,
216 : __func__)) {
217 0 : 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 0 : s_route->oif_ttls[oif_index] = 1;
223 0 : oil_if_set(&s_route->c_oil, oif_index, 1);
224 0 : ++s_route->c_oil.oil_ref_count;
225 :
226 0 : return -1;
227 : }
228 :
229 0 : s_route->c_oil.oif_creation[oif_index] = 0;
230 :
231 0 : if (s_route->c_oil.oil_ref_count <= 0) {
232 0 : listnode_delete(pim->static_routes, s_route);
233 0 : pim_static_route_free(s_route);
234 : }
235 :
236 0 : if (PIM_DEBUG_STATIC) {
237 0 : 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 0 : if (!node) {
248 0 : 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 0 : return -3;
253 : }
254 :
255 : return 0;
256 : }
257 :
258 0 : int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty,
259 : struct interface *ifp)
260 : {
261 0 : struct pim_interface *pim_ifp = ifp->info;
262 0 : struct listnode *node;
263 0 : struct static_route *sroute;
264 0 : int count = 0;
265 :
266 0 : if (!pim_ifp)
267 : return 0;
268 :
269 0 : for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sroute)) {
270 0 : if (sroute->iif == pim_ifp->mroute_vif_index) {
271 : int i;
272 0 : for (i = 0; i < MAXVIFS; i++)
273 0 : if (sroute->oif_ttls[i]) {
274 0 : struct interface *oifp =
275 0 : pim_if_find_by_vif_index(pim,
276 : i);
277 0 : if (pim_addr_is_any(sroute->source))
278 0 : vty_out(vty,
279 : " " PIM_AF_NAME " mroute %s %pPA\n",
280 0 : oifp->name, &sroute->group);
281 : else
282 0 : vty_out(vty,
283 : " " PIM_AF_NAME " mroute %s %pPA %pPA\n",
284 0 : oifp->name, &sroute->group,
285 : &sroute->source);
286 0 : count++;
287 : }
288 : }
289 : }
290 :
291 : return count;
292 : }
|