]>
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
,
47 struct in_addr source
)
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 s_route
->c_oil
.oil
.mfcc_origin
= source
;
58 s_route
->c_oil
.oil
.mfcc_mcastgrp
= group
;
59 s_route
->c_oil
.oil
.mfcc_parent
= iif
;
60 s_route
->c_oil
.oil
.mfcc_ttls
[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
, struct in_addr group
,
69 struct in_addr source
)
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;
79 if (!iif_index
|| !oif_index
|| iif_index
== -1 || oif_index
== -1) {
81 "%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)",
82 __FILE__
, __PRETTY_FUNCTION__
, iif_index
, oif_index
);
86 #ifdef PIM_ENFORCE_LOOPFREE_MFC
87 if (iif_index
== oif_index
) {
88 /* looped MFC entry */
90 "%s %s: Unable to add static route: Looped MFC entry(iif=%d,oif=%d)",
91 __FILE__
, __PRETTY_FUNCTION__
, iif_index
, oif_index
);
95 if (iif
->vrf_id
!= oif
->vrf_id
) {
99 for (ALL_LIST_ELEMENTS_RO(pim
->static_routes
, node
, s_route
)) {
100 if (s_route
->group
.s_addr
== group
.s_addr
101 && s_route
->source
.s_addr
== source
.s_addr
) {
102 if (s_route
->iif
== iif_index
103 && s_route
->oif_ttls
[oif_index
]) {
104 char gifaddr_str
[INET_ADDRSTRLEN
];
105 char sifaddr_str
[INET_ADDRSTRLEN
];
106 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
107 sizeof(gifaddr_str
));
108 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
109 sizeof(sifaddr_str
));
111 "%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)",
112 __FILE__
, __PRETTY_FUNCTION__
,
113 iif_index
, oif_index
, gifaddr_str
,
118 /* Ok, from here on out we will be making changes to the
119 * s_route structure, but if
120 * for some reason we fail to commit these changes to
121 * the kernel, we want to be able
122 * restore the state of the list. So copy the node data
123 * and if need be, we can copy
126 original_s_route
= static_route_alloc();
127 memcpy(original_s_route
, s_route
,
128 sizeof(struct static_route
));
130 /* Route exists and has the same input interface, but
131 * adding a new output interface */
132 if (s_route
->iif
== iif_index
) {
133 s_route
->oif_ttls
[oif_index
] = 1;
134 s_route
->c_oil
.oil
.mfcc_ttls
[oif_index
] = 1;
135 s_route
->c_oil
.oif_creation
[oif_index
] =
136 pim_time_monotonic_sec();
137 ++s_route
->c_oil
.oil_ref_count
;
139 /* input interface changed */
140 s_route
->iif
= iif_index
;
141 pim_channel_oil_change_iif(pim
, &s_route
->c_oil
,
143 __PRETTY_FUNCTION__
);
145 #ifdef PIM_ENFORCE_LOOPFREE_MFC
146 /* check to make sure the new input was not an
148 if (s_route
->oif_ttls
[iif_index
]) {
149 s_route
->oif_ttls
[iif_index
] = 0;
150 s_route
->c_oil
.oif_creation
[iif_index
] =
153 .mfcc_ttls
[iif_index
] = 0;
154 --s_route
->c_oil
.oil_ref_count
;
158 /* now add the new output, if it is new */
159 if (!s_route
->oif_ttls
[oif_index
]) {
160 s_route
->oif_ttls
[oif_index
] = 1;
161 s_route
->c_oil
.oif_creation
[oif_index
] =
162 pim_time_monotonic_sec();
164 .mfcc_ttls
[oif_index
] = 1;
165 ++s_route
->c_oil
.oil_ref_count
;
173 /* If node is null then we reached the end of the list without finding a
176 s_route
= static_route_new(iif_index
, oif_index
, group
, source
);
177 listnode_add(pim
->static_routes
, s_route
);
180 s_route
->c_oil
.pim
= pim
;
182 if (pim_mroute_add(&s_route
->c_oil
, __PRETTY_FUNCTION__
)) {
183 char gifaddr_str
[INET_ADDRSTRLEN
];
184 char sifaddr_str
[INET_ADDRSTRLEN
];
185 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
186 sizeof(gifaddr_str
));
187 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
188 sizeof(sifaddr_str
));
190 "%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)",
191 __FILE__
, __PRETTY_FUNCTION__
, iif_index
, oif_index
,
192 gifaddr_str
, sifaddr_str
);
194 /* Need to put s_route back to the way it was */
195 if (original_s_route
) {
196 memcpy(s_route
, original_s_route
,
197 sizeof(struct static_route
));
199 /* we never stored off a copy, so it must have been a
201 listnode_delete(pim
->static_routes
, s_route
);
202 pim_static_route_free(s_route
);
205 if (original_s_route
) {
206 pim_static_route_free(original_s_route
);
212 /* Make sure we free the memory for the route copy if used */
213 if (original_s_route
) {
214 pim_static_route_free(original_s_route
);
217 if (PIM_DEBUG_STATIC
) {
218 char gifaddr_str
[INET_ADDRSTRLEN
];
219 char sifaddr_str
[INET_ADDRSTRLEN
];
220 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
221 sizeof(gifaddr_str
));
222 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
223 sizeof(sifaddr_str
));
225 "%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)",
226 __PRETTY_FUNCTION__
, iif_index
, oif_index
, gifaddr_str
,
233 int pim_static_del(struct pim_instance
*pim
, struct interface
*iif
,
234 struct interface
*oif
, struct in_addr group
,
235 struct in_addr source
)
237 struct listnode
*node
= NULL
;
238 struct listnode
*nextnode
= NULL
;
239 struct static_route
*s_route
= NULL
;
240 struct pim_interface
*pim_iif
= iif
? iif
->info
: 0;
241 struct pim_interface
*pim_oif
= oif
? oif
->info
: 0;
242 ifindex_t iif_index
= pim_iif
? pim_iif
->mroute_vif_index
: 0;
243 ifindex_t oif_index
= pim_oif
? pim_oif
->mroute_vif_index
: 0;
245 if (!iif_index
|| !oif_index
) {
247 "%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)",
248 __FILE__
, __PRETTY_FUNCTION__
, iif_index
, oif_index
);
252 for (ALL_LIST_ELEMENTS(pim
->static_routes
, node
, nextnode
, s_route
)) {
253 if (s_route
->iif
== iif_index
254 && s_route
->group
.s_addr
== group
.s_addr
255 && s_route
->source
.s_addr
== source
.s_addr
256 && s_route
->oif_ttls
[oif_index
]) {
257 s_route
->oif_ttls
[oif_index
] = 0;
258 s_route
->c_oil
.oil
.mfcc_ttls
[oif_index
] = 0;
259 --s_route
->c_oil
.oil_ref_count
;
261 /* If there are no more outputs then delete the whole
262 * route, otherwise set the route with the new outputs
264 if (s_route
->c_oil
.oil_ref_count
<= 0
265 ? pim_mroute_del(&s_route
->c_oil
,
267 : pim_mroute_add(&s_route
->c_oil
,
268 __PRETTY_FUNCTION__
)) {
269 char gifaddr_str
[INET_ADDRSTRLEN
];
270 char sifaddr_str
[INET_ADDRSTRLEN
];
271 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
272 sizeof(gifaddr_str
));
273 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
274 sizeof(sifaddr_str
));
276 "%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)",
277 __FILE__
, __PRETTY_FUNCTION__
,
278 iif_index
, oif_index
, gifaddr_str
,
281 s_route
->oif_ttls
[oif_index
] = 1;
282 s_route
->c_oil
.oil
.mfcc_ttls
[oif_index
] = 1;
283 ++s_route
->c_oil
.oil_ref_count
;
288 s_route
->c_oil
.oif_creation
[oif_index
] = 0;
290 if (s_route
->c_oil
.oil_ref_count
<= 0) {
291 listnode_delete(pim
->static_routes
, s_route
);
292 pim_static_route_free(s_route
);
295 if (PIM_DEBUG_STATIC
) {
296 char gifaddr_str
[INET_ADDRSTRLEN
];
297 char sifaddr_str
[INET_ADDRSTRLEN
];
298 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
299 sizeof(gifaddr_str
));
300 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
301 sizeof(sifaddr_str
));
303 "%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)",
304 __PRETTY_FUNCTION__
, iif_index
,
305 oif_index
, gifaddr_str
, sifaddr_str
);
313 char gifaddr_str
[INET_ADDRSTRLEN
];
314 char sifaddr_str
[INET_ADDRSTRLEN
];
315 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
316 sizeof(gifaddr_str
));
317 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
318 sizeof(sifaddr_str
));
320 "%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)",
321 __FILE__
, __PRETTY_FUNCTION__
, iif_index
, oif_index
,
322 gifaddr_str
, sifaddr_str
);
329 int pim_static_write_mroute(struct pim_instance
*pim
, struct vty
*vty
,
330 struct interface
*ifp
)
332 struct pim_interface
*pim_ifp
= ifp
->info
;
333 struct listnode
*node
;
334 struct static_route
*sroute
;
336 char sbuf
[INET_ADDRSTRLEN
];
337 char gbuf
[INET_ADDRSTRLEN
];
342 for (ALL_LIST_ELEMENTS_RO(pim
->static_routes
, node
, sroute
)) {
343 pim_inet4_dump("<ifaddr?>", sroute
->group
, gbuf
, sizeof(gbuf
));
344 pim_inet4_dump("<ifaddr?>", sroute
->source
, sbuf
, sizeof(sbuf
));
345 if (sroute
->iif
== pim_ifp
->mroute_vif_index
) {
347 for (i
= 0; i
< MAXVIFS
; i
++)
348 if (sroute
->oif_ttls
[i
]) {
349 struct interface
*oifp
=
350 pim_if_find_by_vif_index(pim
,
352 if (sroute
->source
.s_addr
== 0)
354 " ip mroute %s %s\n",
358 " ip mroute %s %s %s\n",
359 oifp
->name
, gbuf
, sbuf
);