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