]>
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
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
31 #include "pim_static.h"
34 #include "pim_iface.h"
36 void pim_static_route_free(struct static_route
*s_route
)
38 XFREE(MTYPE_PIM_STATIC_ROUTE
, s_route
);
41 static struct static_route
*static_route_alloc()
43 struct static_route
*s_route
;
45 s_route
= XCALLOC(MTYPE_PIM_STATIC_ROUTE
, sizeof(*s_route
));
47 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*s_route
));
53 static struct static_route
*static_route_new(unsigned int iif
, unsigned int oif
,
55 struct in_addr source
)
57 struct static_route
*s_route
;
58 s_route
= static_route_alloc();
63 s_route
->group
= group
;
64 s_route
->source
= source
;
66 s_route
->oif_ttls
[oif
] = 1;
67 s_route
->c_oil
.oil_ref_count
= 1;
68 s_route
->c_oil
.oil
.mfcc_origin
= source
;
69 s_route
->c_oil
.oil
.mfcc_mcastgrp
= group
;
70 s_route
->c_oil
.oil
.mfcc_parent
= iif
;
71 s_route
->c_oil
.oil
.mfcc_ttls
[oif
] = 1;
72 s_route
->c_oil
.oif_creation
[oif
] = pim_time_monotonic_sec();
78 int pim_static_add(struct interface
*iif
, struct interface
*oif
,
79 struct in_addr group
, 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
);
106 for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list
, node
, s_route
)) {
107 if (s_route
->group
.s_addr
== group
.s_addr
108 && s_route
->source
.s_addr
== source
.s_addr
) {
109 if (s_route
->iif
== iif_index
110 && s_route
->oif_ttls
[oif_index
]) {
111 char gifaddr_str
[INET_ADDRSTRLEN
];
112 char sifaddr_str
[INET_ADDRSTRLEN
];
113 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
114 sizeof(gifaddr_str
));
115 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
116 sizeof(sifaddr_str
));
118 "%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)",
119 __FILE__
, __PRETTY_FUNCTION__
,
120 iif_index
, oif_index
, gifaddr_str
,
125 /* Ok, from here on out we will be making changes to the
126 * s_route structure, but if
127 * for some reason we fail to commit these changes to
128 * the kernel, we want to be able
129 * restore the state of the list. So copy the node data
130 * and if need be, we can copy
133 original_s_route
= static_route_alloc();
134 if (!original_s_route
) {
137 memcpy(original_s_route
, s_route
,
138 sizeof(struct static_route
));
140 /* Route exists and has the same input interface, but
141 * adding a new output interface */
142 if (s_route
->iif
== iif_index
) {
143 s_route
->oif_ttls
[oif_index
] = 1;
144 s_route
->c_oil
.oil
.mfcc_ttls
[oif_index
] = 1;
145 s_route
->c_oil
.oif_creation
[oif_index
] =
146 pim_time_monotonic_sec();
147 ++s_route
->c_oil
.oil_ref_count
;
149 /* input interface changed */
150 s_route
->iif
= iif_index
;
151 s_route
->c_oil
.oil
.mfcc_parent
= iif_index
;
153 #ifdef PIM_ENFORCE_LOOPFREE_MFC
154 /* check to make sure the new input was not an
156 if (s_route
->oif_ttls
[iif_index
]) {
157 s_route
->oif_ttls
[iif_index
] = 0;
158 s_route
->c_oil
.oif_creation
[iif_index
] =
161 .mfcc_ttls
[iif_index
] = 0;
162 --s_route
->c_oil
.oil_ref_count
;
166 /* now add the new output, if it is new */
167 if (!s_route
->oif_ttls
[oif_index
]) {
168 s_route
->oif_ttls
[oif_index
] = 1;
169 s_route
->c_oil
.oif_creation
[oif_index
] =
170 pim_time_monotonic_sec();
172 .mfcc_ttls
[oif_index
] = 1;
173 ++s_route
->c_oil
.oil_ref_count
;
181 /* If node is null then we reached the end of the list without finding a
184 s_route
= static_route_new(iif_index
, oif_index
, group
, source
);
185 listnode_add(qpim_static_route_list
, s_route
);
188 if (pim_mroute_add(&s_route
->c_oil
, __PRETTY_FUNCTION__
)) {
189 char gifaddr_str
[INET_ADDRSTRLEN
];
190 char sifaddr_str
[INET_ADDRSTRLEN
];
191 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
192 sizeof(gifaddr_str
));
193 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
194 sizeof(sifaddr_str
));
196 "%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)",
197 __FILE__
, __PRETTY_FUNCTION__
, iif_index
, oif_index
,
198 gifaddr_str
, sifaddr_str
);
200 /* Need to put s_route back to the way it was */
201 if (original_s_route
) {
202 memcpy(s_route
, original_s_route
,
203 sizeof(struct static_route
));
205 /* we never stored off a copy, so it must have been a
207 listnode_delete(qpim_static_route_list
, s_route
);
208 pim_static_route_free(s_route
);
211 if (original_s_route
) {
212 pim_static_route_free(original_s_route
);
218 /* Make sure we free the memory for the route copy if used */
219 if (original_s_route
) {
220 pim_static_route_free(original_s_route
);
223 if (PIM_DEBUG_STATIC
) {
224 char gifaddr_str
[INET_ADDRSTRLEN
];
225 char sifaddr_str
[INET_ADDRSTRLEN
];
226 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
227 sizeof(gifaddr_str
));
228 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
229 sizeof(sifaddr_str
));
231 "%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)",
232 __PRETTY_FUNCTION__
, iif_index
, oif_index
, gifaddr_str
,
239 int pim_static_del(struct interface
*iif
, struct interface
*oif
,
240 struct in_addr group
, struct in_addr source
)
242 struct listnode
*node
= NULL
;
243 struct listnode
*nextnode
= NULL
;
244 struct static_route
*s_route
= NULL
;
245 struct pim_interface
*pim_iif
= iif
? iif
->info
: 0;
246 struct pim_interface
*pim_oif
= oif
? oif
->info
: 0;
247 ifindex_t iif_index
= pim_iif
? pim_iif
->mroute_vif_index
: 0;
248 ifindex_t oif_index
= pim_oif
? pim_oif
->mroute_vif_index
: 0;
250 if (!iif_index
|| !oif_index
) {
252 "%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)",
253 __FILE__
, __PRETTY_FUNCTION__
, iif_index
, oif_index
);
257 for (ALL_LIST_ELEMENTS(qpim_static_route_list
, node
, nextnode
,
259 if (s_route
->iif
== iif_index
260 && s_route
->group
.s_addr
== group
.s_addr
261 && s_route
->source
.s_addr
== source
.s_addr
262 && s_route
->oif_ttls
[oif_index
]) {
263 s_route
->oif_ttls
[oif_index
] = 0;
264 s_route
->c_oil
.oil
.mfcc_ttls
[oif_index
] = 0;
265 --s_route
->c_oil
.oil_ref_count
;
267 /* If there are no more outputs then delete the whole
268 * route, otherwise set the route with the new outputs
270 if (s_route
->c_oil
.oil_ref_count
<= 0
271 ? pim_mroute_del(&s_route
->c_oil
,
273 : pim_mroute_add(&s_route
->c_oil
,
274 __PRETTY_FUNCTION__
)) {
275 char gifaddr_str
[INET_ADDRSTRLEN
];
276 char sifaddr_str
[INET_ADDRSTRLEN
];
277 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
278 sizeof(gifaddr_str
));
279 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
280 sizeof(sifaddr_str
));
282 "%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)",
283 __FILE__
, __PRETTY_FUNCTION__
,
284 iif_index
, oif_index
, gifaddr_str
,
287 s_route
->oif_ttls
[oif_index
] = 1;
288 s_route
->c_oil
.oil
.mfcc_ttls
[oif_index
] = 1;
289 ++s_route
->c_oil
.oil_ref_count
;
294 s_route
->c_oil
.oif_creation
[oif_index
] = 0;
296 if (s_route
->c_oil
.oil_ref_count
<= 0) {
297 listnode_delete(qpim_static_route_list
,
299 pim_static_route_free(s_route
);
302 if (PIM_DEBUG_STATIC
) {
303 char gifaddr_str
[INET_ADDRSTRLEN
];
304 char sifaddr_str
[INET_ADDRSTRLEN
];
305 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
306 sizeof(gifaddr_str
));
307 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
308 sizeof(sifaddr_str
));
310 "%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)",
311 __PRETTY_FUNCTION__
, iif_index
,
312 oif_index
, gifaddr_str
, sifaddr_str
);
320 char gifaddr_str
[INET_ADDRSTRLEN
];
321 char sifaddr_str
[INET_ADDRSTRLEN
];
322 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
,
323 sizeof(gifaddr_str
));
324 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
,
325 sizeof(sifaddr_str
));
327 "%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)",
328 __FILE__
, __PRETTY_FUNCTION__
, iif_index
, oif_index
,
329 gifaddr_str
, sifaddr_str
);
336 int pim_static_write_mroute(struct vty
*vty
, struct interface
*ifp
)
338 struct pim_interface
*pim_ifp
= ifp
->info
;
339 struct listnode
*node
;
340 struct static_route
*sroute
;
342 char sbuf
[INET_ADDRSTRLEN
];
343 char gbuf
[INET_ADDRSTRLEN
];
348 for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list
, node
, sroute
)) {
349 pim_inet4_dump("<ifaddr?>", sroute
->group
, gbuf
, sizeof(gbuf
));
350 pim_inet4_dump("<ifaddr?>", sroute
->source
, sbuf
, sizeof(sbuf
));
351 if (sroute
->iif
== pim_ifp
->mroute_vif_index
) {
353 for (i
= 0; i
< MAXVIFS
; i
++)
354 if (sroute
->oif_ttls
[i
]) {
355 struct interface
*oifp
=
356 pim_if_find_by_vif_index(i
);
357 if (sroute
->source
.s_addr
== 0)
359 " ip mroute %s %s%s",
364 " ip mroute %s %s %s%s",
365 oifp
->name
, gbuf
, sbuf
,