]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_join.c
lib, pimd: Fix borked up prefix code
[mirror_frr.git] / pimd / pim_join.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
12e41d03
DL
20*/
21
22#include <zebra.h>
23
24#include "log.h"
25#include "prefix.h"
744d91b3 26#include "if.h"
12e41d03
DL
27
28#include "pimd.h"
29#include "pim_str.h"
30#include "pim_tlv.h"
31#include "pim_msg.h"
32#include "pim_pim.h"
33#include "pim_join.h"
3667b0bc 34#include "pim_oil.h"
12e41d03
DL
35#include "pim_iface.h"
36#include "pim_hello.h"
37#include "pim_ifchannel.h"
6c629103
DS
38#include "pim_rpf.h"
39#include "pim_rp.h"
12e41d03 40
4950938e
DS
41static void
42on_trace (const char *label,
43 struct interface *ifp, struct in_addr src)
12e41d03
DL
44{
45 if (PIM_DEBUG_PIM_TRACE) {
46 char src_str[100];
47 pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
48 zlog_debug("%s: from %s on %s",
49 label, src_str, ifp->name);
50 }
51}
52
53static void recv_join(struct interface *ifp,
54 struct pim_neighbor *neigh,
55 uint16_t holdtime,
56 struct in_addr upstream,
57 struct in_addr group,
58 struct in_addr source,
59 uint8_t source_flags)
60{
4ed0af70 61 struct prefix_sg sg;
ee1a477a 62
4ed0af70
DS
63 memset (&sg, 0, sizeof (struct prefix_sg));
64 sg.src = source;
65 sg.grp = group;
ee1a477a 66
12e41d03
DL
67 if (PIM_DEBUG_PIM_TRACE) {
68 char up_str[100];
12e41d03
DL
69 char neigh_str[100];
70 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
12e41d03 71 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
ee1a477a 72 zlog_warn("%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
12e41d03 73 __PRETTY_FUNCTION__,
ee1a477a 74 pim_str_sg_dump (&sg),
12e41d03
DL
75 source_flags & PIM_RPT_BIT_MASK,
76 source_flags & PIM_WILDCARD_BIT_MASK,
77 up_str, holdtime, neigh_str, ifp->name);
78 }
346cffe3
DS
79
80 /*
81 * If the RPT and WC are set it's a (*,G)
82 * and the source is the RP
83 */
84 if ((source_flags & PIM_RPT_BIT_MASK) &&
85 (source_flags & PIM_WILDCARD_BIT_MASK))
86 {
4ed0af70 87 struct pim_rpf *rp = RP (sg.grp);
346cffe3
DS
88
89 /*
90 * If the RP sent in the message is not
91 * our RP for the group, drop the message
92 */
4ed0af70 93 if (sg.src.s_addr != rp->rpf_addr.s_addr)
346cffe3
DS
94 return;
95
4ed0af70 96 sg.src.s_addr = INADDR_ANY;
346cffe3
DS
97 }
98
12e41d03
DL
99 /* Restart join expiry timer */
100 pim_ifchannel_join_add(ifp, neigh->source_addr, upstream,
ee1a477a 101 &sg, source_flags, holdtime);
6c629103 102
4ed0af70 103 if (sg.src.s_addr == INADDR_ANY)
6c629103 104 {
3667b0bc
DS
105 struct pim_upstream *up = pim_upstream_find (&sg);
106 struct pim_upstream *child;
107 struct listnode *up_node;
6c629103 108
3667b0bc 109 for (ALL_LIST_ELEMENTS_RO (qpim_upstream_list, up_node, child))
6c629103 110 {
3667b0bc
DS
111 if (child->parent == up)
112 {
113 char buff[100];
114 strcpy (buff, pim_str_sg_dump (&up->sg));
115 zlog_debug("%s %s: Join(S,G)=%s from %s",
116 __FILE__, __PRETTY_FUNCTION__,
117 buff, pim_str_sg_dump (&sg));
118
fa1a4e36
DS
119 pim_channel_add_oif (child->channel_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
120 if (child->join_state != PIM_UPSTREAM_JOINED)
121 pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
3667b0bc 122 }
6c629103
DS
123 }
124 }
125
12e41d03
DL
126}
127
128static void recv_prune(struct interface *ifp,
129 struct pim_neighbor *neigh,
130 uint16_t holdtime,
131 struct in_addr upstream,
132 struct in_addr group,
133 struct in_addr source,
134 uint8_t source_flags)
135{
4ed0af70 136 struct prefix_sg sg;
7bd2c6fa 137
4ed0af70
DS
138 memset (&sg, 0, sizeof (struct prefix_sg));
139 sg.src = source;
140 sg.grp = group;
7bd2c6fa 141
12e41d03
DL
142 if (PIM_DEBUG_PIM_TRACE) {
143 char up_str[100];
12e41d03
DL
144 char neigh_str[100];
145 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
12e41d03 146 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
7bd2c6fa 147 zlog_warn("%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
12e41d03 148 __PRETTY_FUNCTION__,
7bd2c6fa 149 pim_str_sg_dump (&sg),
12e41d03
DL
150 source_flags & PIM_RPT_BIT_MASK,
151 source_flags & PIM_WILDCARD_BIT_MASK,
152 up_str, holdtime, neigh_str, ifp->name);
153 }
035f28f6
DS
154
155 if ((source_flags & PIM_RPT_BIT_MASK) &&
156 (source_flags & PIM_WILDCARD_BIT_MASK))
157 {
4ed0af70 158 struct pim_rpf *rp = RP (sg.grp);
035f28f6
DS
159
160 // Ignoring Prune *,G's at the moment.
4ed0af70 161 if (sg.src.s_addr != rp->rpf_addr.s_addr)
035f28f6
DS
162 return;
163
4ed0af70 164 sg.src.s_addr = INADDR_ANY;
035f28f6 165 }
12e41d03 166
7bd2c6fa 167 pim_ifchannel_prune(ifp, upstream, &sg, source_flags, holdtime);
6c629103 168
4ed0af70 169 if (sg.src.s_addr == INADDR_ANY)
6c629103 170 {
3667b0bc
DS
171 struct pim_upstream *up = pim_upstream_find (&sg);
172 struct pim_upstream *child;
173 struct listnode *up_node;
6c629103 174
3667b0bc 175 for (ALL_LIST_ELEMENTS_RO (qpim_upstream_list, up_node, child))
6c629103 176 {
3667b0bc
DS
177 if (child->parent == up)
178 {
179 char buff[100];
180 strcpy (buff, pim_str_sg_dump (&up->sg));
181 zlog_debug("%s %s: Prune(S,G)=%s from %s",
182 __FILE__, __PRETTY_FUNCTION__,
183 buff, pim_str_sg_dump (&sg));
184 pim_channel_del_oif (up->channel_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
185 }
6c629103
DS
186 }
187 }
188
12e41d03
DL
189}
190
191int pim_joinprune_recv(struct interface *ifp,
192 struct pim_neighbor *neigh,
193 struct in_addr src_addr,
194 uint8_t *tlv_buf, int tlv_buf_size)
195{
196 struct prefix msg_upstream_addr;
197 uint8_t msg_num_groups;
198 uint16_t msg_holdtime;
199 int addr_offset;
200 uint8_t *buf;
201 uint8_t *pastend;
202 int remain;
203 int group;
204
205 on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
206
207 buf = tlv_buf;
208 pastend = tlv_buf + tlv_buf_size;
209
210 /*
211 Parse ucast addr
212 */
4416b1f6
DS
213 addr_offset = pim_parse_addr_ucast (&msg_upstream_addr,
214 buf, pastend - buf);
12e41d03
DL
215 if (addr_offset < 1) {
216 char src_str[100];
217 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
218 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
219 __PRETTY_FUNCTION__,
220 src_str, ifp->name);
221 return -1;
222 }
223 buf += addr_offset;
224
225 /*
226 Check upstream address family
227 */
228 if (msg_upstream_addr.family != AF_INET) {
4950938e 229 if (PIM_DEBUG_PIM_J_P) {
12e41d03
DL
230 char src_str[100];
231 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
232 zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
233 __PRETTY_FUNCTION__,
234 msg_upstream_addr.family, src_str, ifp->name);
235 }
236 return -2;
237 }
238
239 remain = pastend - buf;
240 if (remain < 4) {
241 char src_str[100];
242 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
243 zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
244 __PRETTY_FUNCTION__,
245 remain, 4, src_str, ifp->name);
246 return -4;
247 }
248
249 ++buf; /* skip reserved byte */
250 msg_num_groups = *(const uint8_t *) buf;
251 ++buf;
252 msg_holdtime = ntohs(*(const uint16_t *) buf);
253 ++buf;
254 ++buf;
255
4950938e 256 if (PIM_DEBUG_PIM_J_P) {
12e41d03
DL
257 char src_str[100];
258 char upstream_str[100];
259 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
260 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
261 upstream_str, sizeof(upstream_str));
4950938e
DS
262 zlog_debug ("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
263 __PRETTY_FUNCTION__,
264 upstream_str, msg_num_groups, msg_holdtime,
265 src_str, ifp->name);
12e41d03
DL
266 }
267
268 /* Scan groups */
269 for (group = 0; group < msg_num_groups; ++group) {
270 struct prefix msg_group_addr;
271 struct prefix msg_source_addr;
272 uint8_t msg_source_flags;
273 uint16_t msg_num_joined_sources;
274 uint16_t msg_num_pruned_sources;
275 int source;
276
4416b1f6
DS
277 addr_offset = pim_parse_addr_group (&msg_group_addr,
278 buf, pastend - buf);
12e41d03
DL
279 if (addr_offset < 1) {
280 return -5;
281 }
282 buf += addr_offset;
283
284 remain = pastend - buf;
285 if (remain < 4) {
286 char src_str[100];
287 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
288 zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
289 __PRETTY_FUNCTION__,
290 remain, 4, src_str, ifp->name);
291 return -6;
292 }
293
294 msg_num_joined_sources = ntohs(*(const uint16_t *) buf);
295 buf += 2;
296 msg_num_pruned_sources = ntohs(*(const uint16_t *) buf);
297 buf += 2;
298
4950938e 299 if (PIM_DEBUG_PIM_J_P) {
12e41d03
DL
300 char src_str[100];
301 char upstream_str[100];
302 char group_str[100];
303 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
304 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
305 upstream_str, sizeof(upstream_str));
306 pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4,
307 group_str, sizeof(group_str));
308 zlog_warn("%s: join/prune upstream=%s group=%s/%d join_src=%d prune_src=%d from %s on %s",
309 __PRETTY_FUNCTION__,
310 upstream_str, group_str, msg_group_addr.prefixlen,
311 msg_num_joined_sources, msg_num_pruned_sources,
312 src_str, ifp->name);
313 }
314
315 /* Scan joined sources */
316 for (source = 0; source < msg_num_joined_sources; ++source) {
4416b1f6
DS
317 addr_offset = pim_parse_addr_source (&msg_source_addr,
318 &msg_source_flags,
319 buf, pastend - buf);
12e41d03
DL
320 if (addr_offset < 1) {
321 return -7;
322 }
323
324 buf += addr_offset;
325
326 recv_join(ifp, neigh, msg_holdtime,
327 msg_upstream_addr.u.prefix4,
328 msg_group_addr.u.prefix4,
329 msg_source_addr.u.prefix4,
330 msg_source_flags);
331 }
332
333 /* Scan pruned sources */
334 for (source = 0; source < msg_num_pruned_sources; ++source) {
4416b1f6
DS
335 addr_offset = pim_parse_addr_source (&msg_source_addr,
336 &msg_source_flags,
337 buf, pastend - buf);
12e41d03
DL
338 if (addr_offset < 1) {
339 return -8;
340 }
341
342 buf += addr_offset;
343
344 recv_prune(ifp, neigh, msg_holdtime,
345 msg_upstream_addr.u.prefix4,
346 msg_group_addr.u.prefix4,
347 msg_source_addr.u.prefix4,
348 msg_source_flags);
349 }
350
351 } /* scan groups */
352
353 return 0;
354}
355
356int pim_joinprune_send(struct interface *ifp,
357 struct in_addr upstream_addr,
4ed0af70 358 struct prefix_sg *sg,
12e41d03
DL
359 int send_join)
360{
361 struct pim_interface *pim_ifp;
362 uint8_t pim_msg[1000];
12e41d03 363 int pim_msg_size;
12e41d03 364
4950938e
DS
365 on_trace (__PRETTY_FUNCTION__, ifp, upstream_addr);
366
12e41d03
DL
367 zassert(ifp);
368
369 pim_ifp = ifp->info;
370
371 if (!pim_ifp) {
372 zlog_warn("%s: multicast not enabled on interface %s",
373 __PRETTY_FUNCTION__,
374 ifp->name);
375 return -1;
376 }
377
4950938e 378 if (PIM_DEBUG_PIM_J_P) {
12e41d03 379 char dst_str[100];
12e41d03 380 pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
05e451f8 381 zlog_debug("%s: sending %s(S,G)=%s to upstream=%s on interface %s",
12e41d03
DL
382 __PRETTY_FUNCTION__,
383 send_join ? "Join" : "Prune",
05e451f8 384 pim_str_sg_dump (sg), dst_str, ifp->name);
12e41d03
DL
385 }
386
387 if (PIM_INADDR_IS_ANY(upstream_addr)) {
4950938e 388 if (PIM_DEBUG_PIM_J_P) {
12e41d03 389 char dst_str[100];
12e41d03 390 pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
05e451f8 391 zlog_debug("%s: %s(S,G)=%s: upstream=%s is myself on interface %s",
12e41d03
DL
392 __PRETTY_FUNCTION__,
393 send_join ? "Join" : "Prune",
05e451f8 394 pim_str_sg_dump (sg), dst_str, ifp->name);
12e41d03
DL
395 }
396 return 0;
397 }
398
399 /*
400 RFC 4601: 4.3.1. Sending Hello Messages
401
402 Thus, if a router needs to send a Join/Prune or Assert message on
403 an interface on which it has not yet sent a Hello message with the
404 currently configured IP address, then it MUST immediately send the
405 relevant Hello message without waiting for the Hello Timer to
406 expire, followed by the Join/Prune or Assert message.
407 */
408 pim_hello_require(ifp);
409
410 /*
411 Build PIM message
412 */
346cffe3 413 pim_msg_size = pim_msg_join_prune_encode (pim_msg, 1000, send_join,
4ed0af70 414 sg->src, sg->grp,
346cffe3 415 upstream_addr, PIM_JP_HOLDTIME);
12e41d03 416
346cffe3
DS
417 if (pim_msg_size < 0)
418 return pim_msg_size;
12e41d03
DL
419
420 if (pim_msg_send(pim_ifp->pim_sock_fd,
421 qpim_all_pim_routers_addr,
422 pim_msg,
423 pim_msg_size,
424 ifp->name)) {
425 zlog_warn("%s: could not send PIM message on interface %s",
426 __PRETTY_FUNCTION__, ifp->name);
427 return -8;
428 }
429
430 return 0;
431}