]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_static.c
Merge branch 'frr/pull/92' (BGP Large Community support)
[mirror_frr.git] / pimd / pim_static.c
1 /*
2 PIM for Quagga: add the ability to configure multicast static routes
3 Copyright (C) 2014 Nathan Bahr, ATCorp
4
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.
9
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.
14
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,
18 MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "vty.h"
24 #include "if.h"
25 #include "log.h"
26 #include "memory.h"
27 #include "linklist.h"
28
29 #include "pimd.h"
30 #include "pim_oil.h"
31 #include "pim_static.h"
32 #include "pim_time.h"
33 #include "pim_str.h"
34 #include "pim_iface.h"
35
36 void pim_static_route_free(struct static_route *s_route)
37 {
38 XFREE(MTYPE_PIM_STATIC_ROUTE, s_route);
39 }
40
41 static struct static_route * static_route_alloc()
42 {
43 struct static_route *s_route;
44
45 s_route = XCALLOC(MTYPE_PIM_STATIC_ROUTE, sizeof(*s_route));
46 if (!s_route) {
47 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*s_route));
48 return 0;
49 }
50 return s_route;
51 }
52
53 static struct static_route *static_route_new(unsigned int iif,
54 unsigned int oif,
55 struct in_addr group,
56 struct in_addr source)
57 {
58 struct static_route * s_route;
59 s_route = static_route_alloc();
60 if (!s_route) {
61 return 0;
62 }
63
64 s_route->group = group;
65 s_route->source = source;
66 s_route->iif = iif;
67 s_route->oif_ttls[oif] = 1;
68 s_route->c_oil.oil_ref_count = 1;
69 s_route->c_oil.oil.mfcc_origin = source;
70 s_route->c_oil.oil.mfcc_mcastgrp = group;
71 s_route->c_oil.oil.mfcc_parent = iif;
72 s_route->c_oil.oil.mfcc_ttls[oif] = 1;
73 s_route->c_oil.oif_creation[oif] = pim_time_monotonic_sec();
74
75 return s_route;
76 }
77
78
79 int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source)
80 {
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;
88
89 if (!iif_index || !oif_index) {
90 zlog_warn("%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)",
91 __FILE__, __PRETTY_FUNCTION__,
92 iif_index,
93 oif_index);
94 return -2;
95 }
96
97 #ifdef PIM_ENFORCE_LOOPFREE_MFC
98 if (iif_index == oif_index) {
99 /* looped MFC entry */
100 zlog_warn("%s %s: Unable to add static route: Looped MFC entry(iif=%d,oif=%d)",
101 __FILE__, __PRETTY_FUNCTION__,
102 iif_index,
103 oif_index);
104 return -4;
105 }
106 #endif
107
108 for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) {
109 if (s_route->group.s_addr == group.s_addr &&
110 s_route->source.s_addr == source.s_addr) {
111 if (s_route->iif == iif_index &&
112 s_route->oif_ttls[oif_index]) {
113 char gifaddr_str[INET_ADDRSTRLEN];
114 char sifaddr_str[INET_ADDRSTRLEN];
115 pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
116 pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
117 zlog_warn("%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)",
118 __FILE__, __PRETTY_FUNCTION__,
119 iif_index,
120 oif_index,
121 gifaddr_str,
122 sifaddr_str);
123 return -3;
124 }
125
126 /* Ok, from here on out we will be making changes to the s_route structure, but if
127 * for some reason we fail to commit these changes to the kernel, we want to be able
128 * restore the state of the list. So copy the node data and if need be, we can copy
129 * back if it fails.
130 */
131 original_s_route = static_route_alloc();
132 if (!original_s_route) {
133 return -5;
134 }
135 memcpy(original_s_route, s_route, sizeof(struct static_route));
136
137 /* Route exists and has the same input interface, but adding a new output interface */
138 if (s_route->iif == iif_index) {
139 s_route->oif_ttls[oif_index] = 1;
140 s_route->c_oil.oil.mfcc_ttls[oif_index] = 1;
141 s_route->c_oil.oif_creation[oif_index] = pim_time_monotonic_sec();
142 ++s_route->c_oil.oil_ref_count;
143 } else {
144 /* input interface changed */
145 s_route->iif = iif_index;
146 s_route->c_oil.oil.mfcc_parent = iif_index;
147
148 #ifdef PIM_ENFORCE_LOOPFREE_MFC
149 /* check to make sure the new input was not an old output */
150 if (s_route->oif_ttls[iif_index]) {
151 s_route->oif_ttls[iif_index] = 0;
152 s_route->c_oil.oif_creation[iif_index] = 0;
153 s_route->c_oil.oil.mfcc_ttls[iif_index] = 0;
154 --s_route->c_oil.oil_ref_count;
155 }
156 #endif
157
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] = pim_time_monotonic_sec();
162 s_route->c_oil.oil.mfcc_ttls[oif_index] = 1;
163 ++s_route->c_oil.oil_ref_count;
164 }
165 }
166
167 break;
168 }
169 }
170
171 /* If node is null then we reached the end of the list without finding a match */
172 if (!node) {
173 s_route = static_route_new(iif_index, oif_index, group, source);
174 listnode_add(qpim_static_route_list, s_route);
175 }
176
177 if (pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__))
178 {
179 char gifaddr_str[INET_ADDRSTRLEN];
180 char sifaddr_str[INET_ADDRSTRLEN];
181 pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
182 pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
183 zlog_warn("%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)",
184 __FILE__, __PRETTY_FUNCTION__,
185 iif_index,
186 oif_index,
187 gifaddr_str,
188 sifaddr_str);
189
190 /* Need to put s_route back to the way it was */
191 if (original_s_route) {
192 memcpy(s_route, original_s_route, sizeof(struct static_route));
193 } else {
194 /* we never stored off a copy, so it must have been a fresh new route */
195 listnode_delete(qpim_static_route_list, s_route);
196 pim_static_route_free(s_route);
197 }
198
199 if (original_s_route) {
200 pim_static_route_free(original_s_route);
201 }
202
203 return -1;
204 }
205
206 /* Make sure we free the memory for the route copy if used */
207 if (original_s_route) {
208 pim_static_route_free(original_s_route);
209 }
210
211 if (PIM_DEBUG_STATIC) {
212 char gifaddr_str[INET_ADDRSTRLEN];
213 char sifaddr_str[INET_ADDRSTRLEN];
214 pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
215 pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
216 zlog_debug("%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)",
217 __PRETTY_FUNCTION__,
218 iif_index,
219 oif_index,
220 gifaddr_str,
221 sifaddr_str);
222 }
223
224 return 0;
225 }
226
227 int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source)
228 {
229 struct listnode *node = NULL;
230 struct listnode *nextnode = NULL;
231 struct static_route *s_route = NULL;
232 struct pim_interface *pim_iif = iif ? iif->info : 0;
233 struct pim_interface *pim_oif = oif ? oif->info : 0;
234 ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
235 ifindex_t oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;
236
237 if (!iif_index || !oif_index) {
238 zlog_warn("%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)",
239 __FILE__, __PRETTY_FUNCTION__,
240 iif_index,
241 oif_index);
242 return -2;
243 }
244
245 for (ALL_LIST_ELEMENTS(qpim_static_route_list, node, nextnode, s_route)) {
246 if (s_route->iif == iif_index &&
247 s_route->group.s_addr == group.s_addr &&
248 s_route->source.s_addr == source.s_addr &&
249 s_route->oif_ttls[oif_index]) {
250 s_route->oif_ttls[oif_index] = 0;
251 s_route->c_oil.oil.mfcc_ttls[oif_index] = 0;
252 --s_route->c_oil.oil_ref_count;
253
254 /* If there are no more outputs then delete the whole route, otherwise set the route with the new outputs */
255 if (s_route->c_oil.oil_ref_count <= 0 ?
256 pim_mroute_del(&s_route->c_oil, __PRETTY_FUNCTION__) : pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__)) {
257 char gifaddr_str[INET_ADDRSTRLEN];
258 char sifaddr_str[INET_ADDRSTRLEN];
259 pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
260 pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
261 zlog_warn("%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)",
262 __FILE__, __PRETTY_FUNCTION__,
263 iif_index,
264 oif_index,
265 gifaddr_str,
266 sifaddr_str);
267
268 s_route->oif_ttls[oif_index] = 1;
269 s_route->c_oil.oil.mfcc_ttls[oif_index] = 1;
270 ++s_route->c_oil.oil_ref_count;
271
272 return -1;
273 }
274
275 s_route->c_oil.oif_creation[oif_index] = 0;
276
277 if (s_route->c_oil.oil_ref_count <= 0) {
278 listnode_delete(qpim_static_route_list, s_route);
279 pim_static_route_free(s_route);
280 }
281
282 if (PIM_DEBUG_STATIC) {
283 char gifaddr_str[INET_ADDRSTRLEN];
284 char sifaddr_str[INET_ADDRSTRLEN];
285 pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
286 pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
287 zlog_debug("%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)",
288 __PRETTY_FUNCTION__,
289 iif_index,
290 oif_index,
291 gifaddr_str,
292 sifaddr_str);
293 }
294
295 break;
296 }
297 }
298
299 if (!node) {
300 char gifaddr_str[INET_ADDRSTRLEN];
301 char sifaddr_str[INET_ADDRSTRLEN];
302 pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
303 pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
304 zlog_warn("%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)",
305 __FILE__, __PRETTY_FUNCTION__,
306 iif_index,
307 oif_index,
308 gifaddr_str,
309 sifaddr_str);
310 return -3;
311 }
312
313 return 0;
314 }
315
316 int
317 pim_static_write_mroute (struct vty *vty, struct interface *ifp)
318 {
319 struct listnode *node;
320 struct static_route *sroute;
321 int count = 0;
322 char sbuf[INET_ADDRSTRLEN];
323 char gbuf[INET_ADDRSTRLEN];
324
325 for (ALL_LIST_ELEMENTS_RO (qpim_static_route_list, node, sroute))
326 {
327 pim_inet4_dump ("<ifaddr?>", sroute->group, gbuf, sizeof (gbuf));
328 pim_inet4_dump ("<ifaddr?>", sroute->source, sbuf, sizeof (sbuf));
329 if (sroute->iif == ifp->ifindex)
330 {
331 int i;
332 for (i = 0; i < MAXVIFS; i++)
333 if (sroute->oif_ttls[i])
334 {
335 struct interface *oifp = if_lookup_by_index (i);
336 vty_out (vty, " ip mroute %s %s %s%s", oifp->name, gbuf, sbuf, VTY_NEWLINE);
337 count ++;
338 }
339 }
340 }
341
342 return count;
343 }