]>
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
,
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
, struct in_addr group
, struct in_addr source
)
80 struct listnode
*node
= NULL
;
81 struct static_route
*s_route
= NULL
;
82 struct static_route
*original_s_route
= NULL
;
83 struct pim_interface
*pim_iif
= iif
? iif
->info
: NULL
;
84 struct pim_interface
*pim_oif
= oif
? oif
->info
: NULL
;
85 ifindex_t iif_index
= pim_iif
? pim_iif
->mroute_vif_index
: 0;
86 ifindex_t oif_index
= pim_oif
? pim_oif
->mroute_vif_index
: 0;
88 if (!iif_index
|| !oif_index
) {
89 zlog_warn("%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)",
90 __FILE__
, __PRETTY_FUNCTION__
,
96 #ifdef PIM_ENFORCE_LOOPFREE_MFC
97 if (iif_index
== oif_index
) {
98 /* looped MFC entry */
99 zlog_warn("%s %s: Unable to add static route: Looped MFC entry(iif=%d,oif=%d)",
100 __FILE__
, __PRETTY_FUNCTION__
,
107 for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list
, node
, s_route
)) {
108 if (s_route
->group
.s_addr
== group
.s_addr
&&
109 s_route
->source
.s_addr
== source
.s_addr
) {
110 if (s_route
->iif
== iif_index
&&
111 s_route
->oif_ttls
[oif_index
]) {
112 char gifaddr_str
[INET_ADDRSTRLEN
];
113 char sifaddr_str
[INET_ADDRSTRLEN
];
114 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
, sizeof(gifaddr_str
));
115 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
, sizeof(sifaddr_str
));
116 zlog_warn("%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)",
117 __FILE__
, __PRETTY_FUNCTION__
,
125 /* Ok, from here on out we will be making changes to the s_route structure, but if
126 * for some reason we fail to commit these changes to the kernel, we want to be able
127 * restore the state of the list. So copy the node data and if need be, we can copy
130 original_s_route
= static_route_alloc();
131 if (!original_s_route
) {
134 memcpy(original_s_route
, s_route
, sizeof(struct static_route
));
136 /* Route exists and has the same input interface, but adding a new output interface */
137 if (s_route
->iif
== iif_index
) {
138 s_route
->oif_ttls
[oif_index
] = 1;
139 s_route
->c_oil
.oil
.mfcc_ttls
[oif_index
] = 1;
140 s_route
->c_oil
.oif_creation
[oif_index
] = pim_time_monotonic_sec();
141 ++s_route
->c_oil
.oil_ref_count
;
143 /* input interface changed */
144 s_route
->iif
= iif_index
;
145 s_route
->c_oil
.oil
.mfcc_parent
= iif_index
;
147 #ifdef PIM_ENFORCE_LOOPFREE_MFC
148 /* check to make sure the new input was not an old output */
149 if (s_route
->oif_ttls
[iif_index
]) {
150 s_route
->oif_ttls
[iif_index
] = 0;
151 s_route
->c_oil
.oif_creation
[iif_index
] = 0;
152 s_route
->c_oil
.oil
.mfcc_ttls
[iif_index
] = 0;
153 --s_route
->c_oil
.oil_ref_count
;
157 /* now add the new output, if it is new */
158 if (!s_route
->oif_ttls
[oif_index
]) {
159 s_route
->oif_ttls
[oif_index
] = 1;
160 s_route
->c_oil
.oif_creation
[oif_index
] = pim_time_monotonic_sec();
161 s_route
->c_oil
.oil
.mfcc_ttls
[oif_index
] = 1;
162 ++s_route
->c_oil
.oil_ref_count
;
170 /* If node is null then we reached the end of the list without finding a match */
172 s_route
= static_route_new(iif_index
, oif_index
, group
, source
);
173 listnode_add(qpim_static_route_list
, s_route
);
176 if (pim_mroute_add(&s_route
->c_oil
, __PRETTY_FUNCTION__
))
178 char gifaddr_str
[INET_ADDRSTRLEN
];
179 char sifaddr_str
[INET_ADDRSTRLEN
];
180 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
, sizeof(gifaddr_str
));
181 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
, sizeof(sifaddr_str
));
182 zlog_warn("%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)",
183 __FILE__
, __PRETTY_FUNCTION__
,
189 /* Need to put s_route back to the way it was */
190 if (original_s_route
) {
191 memcpy(s_route
, original_s_route
, sizeof(struct static_route
));
193 /* we never stored off a copy, so it must have been a fresh new route */
194 listnode_delete(qpim_static_route_list
, s_route
);
195 pim_static_route_free(s_route
);
198 if (original_s_route
) {
199 pim_static_route_free(original_s_route
);
205 /* Make sure we free the memory for the route copy if used */
206 if (original_s_route
) {
207 pim_static_route_free(original_s_route
);
210 if (PIM_DEBUG_STATIC
) {
211 char gifaddr_str
[INET_ADDRSTRLEN
];
212 char sifaddr_str
[INET_ADDRSTRLEN
];
213 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
, sizeof(gifaddr_str
));
214 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
, sizeof(sifaddr_str
));
215 zlog_debug("%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)",
226 int pim_static_del(struct interface
*iif
, struct interface
*oif
, struct in_addr group
, struct in_addr source
)
228 struct listnode
*node
= NULL
;
229 struct listnode
*nextnode
= NULL
;
230 struct static_route
*s_route
= NULL
;
231 struct pim_interface
*pim_iif
= iif
? iif
->info
: 0;
232 struct pim_interface
*pim_oif
= oif
? oif
->info
: 0;
233 ifindex_t iif_index
= pim_iif
? pim_iif
->mroute_vif_index
: 0;
234 ifindex_t oif_index
= pim_oif
? pim_oif
->mroute_vif_index
: 0;
236 if (!iif_index
|| !oif_index
) {
237 zlog_warn("%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)",
238 __FILE__
, __PRETTY_FUNCTION__
,
244 for (ALL_LIST_ELEMENTS(qpim_static_route_list
, node
, nextnode
, s_route
)) {
245 if (s_route
->iif
== iif_index
&&
246 s_route
->group
.s_addr
== group
.s_addr
&&
247 s_route
->source
.s_addr
== source
.s_addr
&&
248 s_route
->oif_ttls
[oif_index
]) {
249 s_route
->oif_ttls
[oif_index
] = 0;
250 s_route
->c_oil
.oil
.mfcc_ttls
[oif_index
] = 0;
251 --s_route
->c_oil
.oil_ref_count
;
253 /* If there are no more outputs then delete the whole route, otherwise set the route with the new outputs */
254 if (s_route
->c_oil
.oil_ref_count
<= 0 ?
255 pim_mroute_del(&s_route
->c_oil
, __PRETTY_FUNCTION__
) : pim_mroute_add(&s_route
->c_oil
, __PRETTY_FUNCTION__
)) {
256 char gifaddr_str
[INET_ADDRSTRLEN
];
257 char sifaddr_str
[INET_ADDRSTRLEN
];
258 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
, sizeof(gifaddr_str
));
259 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
, sizeof(sifaddr_str
));
260 zlog_warn("%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)",
261 __FILE__
, __PRETTY_FUNCTION__
,
267 s_route
->oif_ttls
[oif_index
] = 1;
268 s_route
->c_oil
.oil
.mfcc_ttls
[oif_index
] = 1;
269 ++s_route
->c_oil
.oil_ref_count
;
274 s_route
->c_oil
.oif_creation
[oif_index
] = 0;
276 if (s_route
->c_oil
.oil_ref_count
<= 0) {
277 listnode_delete(qpim_static_route_list
, s_route
);
278 pim_static_route_free(s_route
);
281 if (PIM_DEBUG_STATIC
) {
282 char gifaddr_str
[INET_ADDRSTRLEN
];
283 char sifaddr_str
[INET_ADDRSTRLEN
];
284 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
, sizeof(gifaddr_str
));
285 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
, sizeof(sifaddr_str
));
286 zlog_debug("%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)",
299 char gifaddr_str
[INET_ADDRSTRLEN
];
300 char sifaddr_str
[INET_ADDRSTRLEN
];
301 pim_inet4_dump("<ifaddr?>", group
, gifaddr_str
, sizeof(gifaddr_str
));
302 pim_inet4_dump("<ifaddr?>", source
, sifaddr_str
, sizeof(sifaddr_str
));
303 zlog_warn("%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)",
304 __FILE__
, __PRETTY_FUNCTION__
,
316 pim_static_write_mroute (struct vty
*vty
, struct interface
*ifp
)
318 struct pim_interface
*pim_ifp
= ifp
->info
;
319 struct listnode
*node
;
320 struct static_route
*sroute
;
322 char sbuf
[INET_ADDRSTRLEN
];
323 char gbuf
[INET_ADDRSTRLEN
];
328 for (ALL_LIST_ELEMENTS_RO (qpim_static_route_list
, node
, sroute
))
330 pim_inet4_dump ("<ifaddr?>", sroute
->group
, gbuf
, sizeof (gbuf
));
331 pim_inet4_dump ("<ifaddr?>", sroute
->source
, sbuf
, sizeof (sbuf
));
332 if (sroute
->iif
== pim_ifp
->mroute_vif_index
)
335 for (i
= 0; i
< MAXVIFS
; i
++)
336 if (sroute
->oif_ttls
[i
])
338 struct interface
*oifp
= pim_if_find_by_vif_index (i
);
339 if (sroute
->source
.s_addr
== 0)
340 vty_out (vty
, " ip mroute %s %s%s", oifp
->name
, gbuf
, VTY_NEWLINE
);
342 vty_out (vty
, " ip mroute %s %s %s%s", oifp
->name
, gbuf
, sbuf
, VTY_NEWLINE
);