]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_oil.c
pimd: Make received packet zlog_err a zlog_debug
[mirror_frr.git] / pimd / pim_oil.c
CommitLineData
12e41d03
DL
1/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
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 $QuaggaId: $Format:%an, %ai, %h$ $
21*/
22
23#include <zebra.h>
24
25#include "log.h"
26#include "memory.h"
27#include "linklist.h"
744d91b3 28#include "if.h"
12e41d03
DL
29
30#include "pimd.h"
31#include "pim_oil.h"
32#include "pim_str.h"
33#include "pim_iface.h"
37653d4f 34#include "pim_time.h"
12e41d03
DL
35
36void pim_channel_oil_free(struct channel_oil *c_oil)
37{
38 XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil);
39}
40
41static void pim_channel_oil_delete(struct channel_oil *c_oil)
42{
43 /*
44 notice that listnode_delete() can't be moved
45 into pim_channel_oil_free() because the later is
46 called by list_delete_all_node()
47 */
48 listnode_delete(qpim_channel_oil_list, c_oil);
49
50 pim_channel_oil_free(c_oil);
51}
52
53static struct channel_oil *channel_oil_new(struct in_addr group_addr,
54 struct in_addr source_addr,
55 int input_vif_index)
56{
57 struct channel_oil *c_oil;
58 struct interface *ifp_in;
59
60 ifp_in = pim_if_find_by_vif_index(input_vif_index);
61 if (!ifp_in) {
62 /* warning only */
63 char group_str[100];
64 char source_str[100];
65 pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
66 pim_inet4_dump("<source?>", source_addr, source_str, sizeof(source_str));
67 zlog_warn("%s: (S,G)=(%s,%s) could not find input interface for input_vif_index=%d",
68 __PRETTY_FUNCTION__,
69 source_str, group_str, input_vif_index);
70 }
71
72 c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil));
73 if (!c_oil) {
74 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*c_oil));
75 return 0;
76 }
77
78 c_oil->oil.mfcc_mcastgrp = group_addr;
79 c_oil->oil.mfcc_origin = source_addr;
80 c_oil->oil.mfcc_parent = input_vif_index;
81 c_oil->oil_ref_count = 1;
82
83 zassert(c_oil->oil_size == 0);
84
85 return c_oil;
86}
87
88static struct channel_oil *pim_add_channel_oil(struct in_addr group_addr,
89 struct in_addr source_addr,
90 int input_vif_index)
91{
92 struct channel_oil *c_oil;
93
94 c_oil = channel_oil_new(group_addr, source_addr, input_vif_index);
95 if (!c_oil) {
96 zlog_warn("PIM XCALLOC(%zu) failure", sizeof(*c_oil));
97 return 0;
98 }
99
100 listnode_add(qpim_channel_oil_list, c_oil);
101
102 return c_oil;
103}
104
105static struct channel_oil *pim_find_channel_oil(struct in_addr group_addr,
106 struct in_addr source_addr)
107{
108 struct listnode *node;
109 struct channel_oil *c_oil;
110
111 for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) {
112 if ((group_addr.s_addr == c_oil->oil.mfcc_mcastgrp.s_addr) &&
113 (source_addr.s_addr == c_oil->oil.mfcc_origin.s_addr))
114 return c_oil;
115 }
116
117 return 0;
118}
119
120struct channel_oil *pim_channel_oil_add(struct in_addr group_addr,
121 struct in_addr source_addr,
122 int input_vif_index)
123{
124 struct channel_oil *c_oil;
125
126 c_oil = pim_find_channel_oil(group_addr, source_addr);
127 if (c_oil) {
128 ++c_oil->oil_ref_count;
129 return c_oil;
130 }
131
132 return pim_add_channel_oil(group_addr, source_addr, input_vif_index);
133}
134
135void pim_channel_oil_del(struct channel_oil *c_oil)
136{
137 --c_oil->oil_ref_count;
138
139 if (c_oil->oil_ref_count < 1) {
140 pim_channel_oil_delete(c_oil);
141 }
142}
1865a44a
DS
143
144int pim_channel_add_oif(struct channel_oil *channel_oil,
145 struct interface *oif,
146 uint32_t proto_mask)
147{
148 struct pim_interface *pim_ifp;
149 int old_ttl;
150
151 zassert(channel_oil);
152
153 pim_ifp = oif->info;
154
155 if (PIM_DEBUG_MROUTE) {
156 char group_str[100];
157 char source_str[100];
158 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
159 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
160 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
161 __FILE__, __PRETTY_FUNCTION__,
162 source_str, group_str,
163 proto_mask, oif->name, pim_ifp->mroute_vif_index);
164 }
165
1865a44a
DS
166#ifdef PIM_ENFORCE_LOOPFREE_MFC
167 /*
168 Prevent creating MFC entry with OIF=IIF.
169
170 This is a protection against implementation mistakes.
171
172 PIM protocol implicitely ensures loopfree multicast topology.
173
174 IGMP must be protected against adding looped MFC entries created
175 by both source and receiver attached to the same interface. See
176 TODO T22.
177 */
178 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
179 char group_str[100];
180 char source_str[100];
181 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
182 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
183 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
184 __FILE__, __PRETTY_FUNCTION__,
185 proto_mask, oif->name, pim_ifp->mroute_vif_index,
186 source_str, group_str);
187 return -2;
188 }
189#endif
190
1865a44a
DS
191 /* Prevent single protocol from subscribing same interface to
192 channel (S,G) multiple times */
193 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
194 char group_str[100];
195 char source_str[100];
196 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
197 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
198 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
199 __FILE__, __PRETTY_FUNCTION__,
200 proto_mask, oif->name, pim_ifp->mroute_vif_index,
201 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
202 source_str, group_str);
203 return -3;
204 }
205
206 /* Allow other protocol to request subscription of same interface to
207 channel (S,G) multiple times, by silently ignoring further
208 requests */
209 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
210
211 /* Check the OIF really exists before returning, and only log
212 warning otherwise */
213 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
214 char group_str[100];
215 char source_str[100];
216 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
217 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
218 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
219 __FILE__, __PRETTY_FUNCTION__,
220 proto_mask, oif->name, pim_ifp->mroute_vif_index,
221 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
222 source_str, group_str);
223 }
224
225 return 0;
226 }
227
228 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
229
230 if (old_ttl > 0) {
231 char group_str[100];
232 char source_str[100];
233 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
234 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
235 zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
236 __FILE__, __PRETTY_FUNCTION__,
237 oif->name, pim_ifp->mroute_vif_index,
238 source_str, group_str);
239 return -4;
240 }
241
242 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
243
244 if (pim_mroute_add(&channel_oil->oil)) {
245 char group_str[100];
246 char source_str[100];
247 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
248 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
249 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
250 __FILE__, __PRETTY_FUNCTION__,
251 oif->name, pim_ifp->mroute_vif_index,
252 source_str, group_str);
253
254 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
255 return -5;
256 }
257
258 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
259 ++channel_oil->oil_size;
260 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
261
262 if (PIM_DEBUG_MROUTE) {
263 char group_str[100];
264 char source_str[100];
265 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
266 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
267 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
268 __FILE__, __PRETTY_FUNCTION__,
269 source_str, group_str,
270 proto_mask, oif->name, pim_ifp->mroute_vif_index);
271 }
272
273 return 0;
274}