]>
git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_static.c
2 * PIM for Quagga: add the ability to configure multicast static routes
3 * Copyright (C) 2014 Nathan Bahr, ATCorp
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.
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.
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
30 #include "pim_static.h"
33 #include "pim_iface.h"
35 void pim_static_route_free(struct static_route
*s_route
)
37 XFREE(MTYPE_PIM_STATIC_ROUTE
, s_route
);
40 static struct static_route
*static_route_alloc(void)
42 return XCALLOC(MTYPE_PIM_STATIC_ROUTE
, sizeof(struct static_route
));
45 static struct static_route
*static_route_new(ifindex_t iif
, ifindex_t oif
,
49 struct static_route
*s_route
;
50 s_route
= static_route_alloc();
52 s_route
->group
= group
;
53 s_route
->source
= source
;
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();
67 int pim_static_add(struct pim_instance
*pim
, struct interface
*iif
,
68 struct interface
*oif
, pim_addr group
, pim_addr source
)
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;
78 if (!iif_index
|| !oif_index
|| iif_index
== -1 || oif_index
== -1) {
80 "%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)",
81 __FILE__
, __func__
, iif_index
, oif_index
);
85 #ifdef PIM_ENFORCE_LOOPFREE_MFC
86 if (iif_index
== oif_index
) {
87 /* looped MFC entry */
89 "%s %s: Unable to add static route: Looped MFC entry(iif=%d,oif=%d)",
90 __FILE__
, __func__
, iif_index
, oif_index
);
94 if (iif
->vrf
->vrf_id
!= oif
->vrf
->vrf_id
) {
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
]) {
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
);
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
118 original_s_route
= static_route_alloc();
119 memcpy(original_s_route
, s_route
,
120 sizeof(struct static_route
));
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
;
131 /* input interface changed */
132 s_route
->iif
= iif_index
;
133 pim_static_mroute_iif_update(
134 &s_route
->c_oil
, iif_index
, __func__
);
136 #ifdef PIM_ENFORCE_LOOPFREE_MFC
137 /* check to make sure the new input was not an
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
] =
143 oil_if_set(&s_route
->c_oil
, iif_index
,
145 --s_route
->c_oil
.oil_ref_count
;
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
,
156 ++s_route
->c_oil
.oil_ref_count
;
164 /* If node is null then we reached the end of the list without finding a
167 s_route
= static_route_new(iif_index
, oif_index
, group
, source
);
168 listnode_add(pim
->static_routes
, s_route
);
171 s_route
->c_oil
.pim
= pim
;
173 if (pim_static_mroute_add(&s_route
->c_oil
, __func__
)) {
175 "%s %s: Unable to add static route(iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
176 __FILE__
, __func__
, iif_index
, oif_index
, &group
,
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
));
184 /* we never stored off a copy, so it must have been a
186 listnode_delete(pim
->static_routes
, s_route
);
187 pim_static_route_free(s_route
);
190 if (original_s_route
) {
191 pim_static_route_free(original_s_route
);
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
);
202 if (PIM_DEBUG_STATIC
) {
204 "%s: Static route added(iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
205 __func__
, iif_index
, oif_index
, &group
,
212 int pim_static_del(struct pim_instance
*pim
, struct interface
*iif
,
213 struct interface
*oif
, pim_addr group
, pim_addr source
)
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;
223 if (!iif_index
|| !oif_index
) {
225 "%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)",
226 __FILE__
, __func__
, iif_index
, oif_index
);
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
;
239 /* If there are no more outputs then delete the whole
240 * route, otherwise set the route with the new outputs
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
,
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
);
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
;
258 s_route
->c_oil
.oif_creation
[oif_index
] = 0;
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
);
265 if (PIM_DEBUG_STATIC
) {
267 "%s: Static route removed(iif=%d,oif=%d,group=%pPAs,source=%pPAs)",
268 __func__
, iif_index
, oif_index
,
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
,
287 int pim_static_write_mroute(struct pim_instance
*pim
, struct vty
*vty
,
288 struct interface
*ifp
)
290 struct pim_interface
*pim_ifp
= ifp
->info
;
291 struct listnode
*node
;
292 struct static_route
*sroute
;
298 for (ALL_LIST_ELEMENTS_RO(pim
->static_routes
, node
, sroute
)) {
299 if (sroute
->iif
== pim_ifp
->mroute_vif_index
) {
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
,
306 if (pim_addr_is_any(sroute
->source
))
308 " " PIM_AF_NAME
" mroute %s %pPA\n",
309 oifp
->name
, &sroute
->group
);
312 " " PIM_AF_NAME
" mroute %s %pPA %pPA\n",
313 oifp
->name
, &sroute
->group
,