]>
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()
42 struct static_route
*s_route
;
44 s_route
= XCALLOC(MTYPE_PIM_STATIC_ROUTE
, sizeof(*s_route
));
46 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*s_route
));
52 static struct static_route
*static_route_new(unsigned int iif
, unsigned int oif
,
54 struct in_addr source
)
56 struct static_route
*s_route
;
57 s_route
= static_route_alloc();
62 s_route
->group
= group
;
63 s_route
->source
= source
;
65 s_route
->oif_ttls
[oif
] = 1;
66 s_route
->c_oil
.oil_ref_count
= 1;
67 s_route
->c_oil
.oil
.mfcc_origin
= source
;
68 s_route
->c_oil
.oil
.mfcc_mcastgrp
= group
;
69 s_route
->c_oil
.oil
.mfcc_parent
= iif
;
70 s_route
->c_oil
.oil
.mfcc_ttls
[oif
] = 1;
71 s_route
->c_oil
.oif_creation
[oif
] = pim_time_monotonic_sec();
77 int pim_static_add(struct pim_instance
*pim
, struct interface
*iif
,
78 struct interface
*oif
, struct in_addr group
,
79 struct in_addr source
)
81 struct listnode
*node
= NULL
;
82 struct static_route
*s_route
= NULL
;
83 struct static_route
*original_s_route
= NULL
;
84 struct pim_interface
*pim_iif
= iif
? iif
->info
: NULL
;
85 struct pim_interface
*pim_oif
= oif
? oif
->info
: NULL
;
86 ifindex_t iif_index
= pim_iif
? pim_iif
->mroute_vif_index
: 0;
87 ifindex_t oif_index
= pim_oif
? pim_oif
->mroute_vif_index
: 0;
89 if (!iif_index
|| !oif_index
) {
91 "%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)",
92 __FILE__
, __PRETTY_FUNCTION__
, iif_index
, oif_index
);
96 #ifdef PIM_ENFORCE_LOOPFREE_MFC
97 if (iif_index
== oif_index
) {
98 /* looped MFC entry */
100 "%s %s: Unable to add static route: Looped MFC entry(iif=%d,oif=%d)",
101 __FILE__
, __PRETTY_FUNCTION__
, iif_index
, oif_index
);
105 if (iif
->vrf_id
!= oif
->vrf_id
) {
109 for (ALL_LIST_ELEMENTS_RO(pim
->static_routes
, node
, s_route
)) {
110 if (s_route
->group
.s_addr
== group
.s_addr
111 && s_route
->source
.s_addr
== source
.s_addr
) {
112 if (s_route
->iif
== iif_index
113 && s_route
->oif_ttls
[oif_index
]) {
114 char gifaddr_str
[INET_ADDRSTRLEN
];
115 char sifaddr_str
[INET_ADDRSTRLEN
];
116 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
117 sizeof(gifaddr_str
));
118 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
119 sizeof(sifaddr_str
));
121 "%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)",
122 __FILE__
, __PRETTY_FUNCTION__
,
123 iif_index
, oif_index
, gifaddr_str
,
128 /* Ok, from here on out we will be making changes to the
129 * s_route structure, but if
130 * for some reason we fail to commit these changes to
131 * the kernel, we want to be able
132 * restore the state of the list. So copy the node data
133 * and if need be, we can copy
136 original_s_route
= static_route_alloc();
137 if (!original_s_route
) {
140 memcpy(original_s_route
, s_route
,
141 sizeof(struct static_route
));
143 /* Route exists and has the same input interface, but
144 * adding a new output interface */
145 if (s_route
->iif
== iif_index
) {
146 s_route
->oif_ttls
[oif_index
] = 1;
147 s_route
->c_oil
.oil
.mfcc_ttls
[oif_index
] = 1;
148 s_route
->c_oil
.oif_creation
[oif_index
] =
149 pim_time_monotonic_sec();
150 ++s_route
->c_oil
.oil_ref_count
;
152 /* input interface changed */
153 s_route
->iif
= iif_index
;
154 s_route
->c_oil
.oil
.mfcc_parent
= iif_index
;
156 #ifdef PIM_ENFORCE_LOOPFREE_MFC
157 /* check to make sure the new input was not an
159 if (s_route
->oif_ttls
[iif_index
]) {
160 s_route
->oif_ttls
[iif_index
] = 0;
161 s_route
->c_oil
.oif_creation
[iif_index
] =
164 .mfcc_ttls
[iif_index
] = 0;
165 --s_route
->c_oil
.oil_ref_count
;
169 /* now add the new output, if it is new */
170 if (!s_route
->oif_ttls
[oif_index
]) {
171 s_route
->oif_ttls
[oif_index
] = 1;
172 s_route
->c_oil
.oif_creation
[oif_index
] =
173 pim_time_monotonic_sec();
175 .mfcc_ttls
[oif_index
] = 1;
176 ++s_route
->c_oil
.oil_ref_count
;
184 /* If node is null then we reached the end of the list without finding a
187 s_route
= static_route_new(iif_index
, oif_index
, group
, source
);
188 listnode_add(pim
->static_routes
, s_route
);
191 s_route
->c_oil
.pim
= pim
;
193 if (pim_mroute_add(&s_route
->c_oil
, __PRETTY_FUNCTION__
)) {
194 char gifaddr_str
[INET_ADDRSTRLEN
];
195 char sifaddr_str
[INET_ADDRSTRLEN
];
196 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
197 sizeof(gifaddr_str
));
198 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
199 sizeof(sifaddr_str
));
201 "%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)",
202 __FILE__
, __PRETTY_FUNCTION__
, iif_index
, oif_index
,
203 gifaddr_str
, sifaddr_str
);
205 /* Need to put s_route back to the way it was */
206 if (original_s_route
) {
207 memcpy(s_route
, original_s_route
,
208 sizeof(struct static_route
));
210 /* we never stored off a copy, so it must have been a
212 listnode_delete(pim
->static_routes
, s_route
);
213 pim_static_route_free(s_route
);
216 if (original_s_route
) {
217 pim_static_route_free(original_s_route
);
223 /* Make sure we free the memory for the route copy if used */
224 if (original_s_route
) {
225 pim_static_route_free(original_s_route
);
228 if (PIM_DEBUG_STATIC
) {
229 char gifaddr_str
[INET_ADDRSTRLEN
];
230 char sifaddr_str
[INET_ADDRSTRLEN
];
231 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
232 sizeof(gifaddr_str
));
233 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
234 sizeof(sifaddr_str
));
236 "%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)",
237 __PRETTY_FUNCTION__
, iif_index
, oif_index
, gifaddr_str
,
244 int pim_static_del(struct pim_instance
*pim
, struct interface
*iif
,
245 struct interface
*oif
, struct in_addr group
,
246 struct in_addr source
)
248 struct listnode
*node
= NULL
;
249 struct listnode
*nextnode
= NULL
;
250 struct static_route
*s_route
= NULL
;
251 struct pim_interface
*pim_iif
= iif
? iif
->info
: 0;
252 struct pim_interface
*pim_oif
= oif
? oif
->info
: 0;
253 ifindex_t iif_index
= pim_iif
? pim_iif
->mroute_vif_index
: 0;
254 ifindex_t oif_index
= pim_oif
? pim_oif
->mroute_vif_index
: 0;
256 if (!iif_index
|| !oif_index
) {
258 "%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)",
259 __FILE__
, __PRETTY_FUNCTION__
, iif_index
, oif_index
);
263 for (ALL_LIST_ELEMENTS(pim
->static_routes
, node
, nextnode
, s_route
)) {
264 if (s_route
->iif
== iif_index
265 && s_route
->group
.s_addr
== group
.s_addr
266 && s_route
->source
.s_addr
== source
.s_addr
267 && s_route
->oif_ttls
[oif_index
]) {
268 s_route
->oif_ttls
[oif_index
] = 0;
269 s_route
->c_oil
.oil
.mfcc_ttls
[oif_index
] = 0;
270 --s_route
->c_oil
.oil_ref_count
;
272 /* If there are no more outputs then delete the whole
273 * route, otherwise set the route with the new outputs
275 if (s_route
->c_oil
.oil_ref_count
<= 0
276 ? pim_mroute_del(&s_route
->c_oil
,
278 : pim_mroute_add(&s_route
->c_oil
,
279 __PRETTY_FUNCTION__
)) {
280 char gifaddr_str
[INET_ADDRSTRLEN
];
281 char sifaddr_str
[INET_ADDRSTRLEN
];
282 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
283 sizeof(gifaddr_str
));
284 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
285 sizeof(sifaddr_str
));
287 "%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)",
288 __FILE__
, __PRETTY_FUNCTION__
,
289 iif_index
, oif_index
, gifaddr_str
,
292 s_route
->oif_ttls
[oif_index
] = 1;
293 s_route
->c_oil
.oil
.mfcc_ttls
[oif_index
] = 1;
294 ++s_route
->c_oil
.oil_ref_count
;
299 s_route
->c_oil
.oif_creation
[oif_index
] = 0;
301 if (s_route
->c_oil
.oil_ref_count
<= 0) {
302 listnode_delete(pim
->static_routes
, s_route
);
303 pim_static_route_free(s_route
);
306 if (PIM_DEBUG_STATIC
) {
307 char gifaddr_str
[INET_ADDRSTRLEN
];
308 char sifaddr_str
[INET_ADDRSTRLEN
];
309 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
310 sizeof(gifaddr_str
));
311 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
312 sizeof(sifaddr_str
));
314 "%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)",
315 __PRETTY_FUNCTION__
, iif_index
,
316 oif_index
, gifaddr_str
, sifaddr_str
);
324 char gifaddr_str
[INET_ADDRSTRLEN
];
325 char sifaddr_str
[INET_ADDRSTRLEN
];
326 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
327 sizeof(gifaddr_str
));
328 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
329 sizeof(sifaddr_str
));
331 "%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)",
332 __FILE__
, __PRETTY_FUNCTION__
, iif_index
, oif_index
,
333 gifaddr_str
, sifaddr_str
);
340 int pim_static_write_mroute(struct pim_instance
*pim
, struct vty
*vty
,
341 struct interface
*ifp
)
343 struct pim_interface
*pim_ifp
= ifp
->info
;
344 struct listnode
*node
;
345 struct static_route
*sroute
;
347 char sbuf
[INET_ADDRSTRLEN
];
348 char gbuf
[INET_ADDRSTRLEN
];
353 for (ALL_LIST_ELEMENTS_RO(pim
->static_routes
, node
, sroute
)) {
354 pim_inet4_dump("<ifaddr?>", sroute
->group
, gbuf
, sizeof(gbuf
));
355 pim_inet4_dump("<ifaddr?>", sroute
->source
, sbuf
, sizeof(sbuf
));
356 if (sroute
->iif
== pim_ifp
->mroute_vif_index
) {
358 for (i
= 0; i
< MAXVIFS
; i
++)
359 if (sroute
->oif_ttls
[i
]) {
360 struct interface
*oifp
=
361 pim_if_find_by_vif_index(pim
,
363 if (sroute
->source
.s_addr
== 0)
365 " ip mroute %s %s\n",
369 " ip mroute %s %s %s\n",
370 oifp
->name
, gbuf
, sbuf
);