]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_join.c
Merge pull request #537 from donaldsharp/vrf_stuff
[mirror_frr.git] / pimd / pim_join.c
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 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
18 */
19
20 #include <zebra.h>
21
22 #include "log.h"
23 #include "prefix.h"
24 #include "if.h"
25 #include "vty.h"
26 #include "plist.h"
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"
34 #include "pim_oil.h"
35 #include "pim_iface.h"
36 #include "pim_hello.h"
37 #include "pim_ifchannel.h"
38 #include "pim_rpf.h"
39 #include "pim_rp.h"
40 #include "pim_jp_agg.h"
41
42 static void
43 on_trace (const char *label,
44 struct interface *ifp, struct in_addr src)
45 {
46 if (PIM_DEBUG_PIM_TRACE) {
47 char src_str[INET_ADDRSTRLEN];
48 pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
49 zlog_debug("%s: from %s on %s",
50 label, src_str, ifp->name);
51 }
52 }
53
54 static void recv_join(struct interface *ifp,
55 struct pim_neighbor *neigh,
56 uint16_t holdtime,
57 struct in_addr upstream,
58 struct prefix_sg *sg,
59 uint8_t source_flags)
60 {
61 struct pim_interface *pim_ifp = NULL;
62
63 if (PIM_DEBUG_PIM_TRACE) {
64 char up_str[INET_ADDRSTRLEN];
65 char neigh_str[INET_ADDRSTRLEN];
66 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
67 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
68 zlog_warn("%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
69 __PRETTY_FUNCTION__,
70 pim_str_sg_dump (sg),
71 source_flags & PIM_RPT_BIT_MASK,
72 source_flags & PIM_WILDCARD_BIT_MASK,
73 up_str, holdtime, neigh_str, ifp->name);
74 }
75
76 pim_ifp = ifp->info;
77 zassert(pim_ifp);
78
79 ++pim_ifp->pim_ifstat_join_recv;
80
81 /*
82 * If the RPT and WC are set it's a (*,G)
83 * and the source is the RP
84 */
85 if ((source_flags & PIM_RPT_BIT_MASK) &&
86 (source_flags & PIM_WILDCARD_BIT_MASK))
87 {
88 struct pim_rpf *rp = RP (sg->grp);
89
90 /*
91 * If the RP sent in the message is not
92 * our RP for the group, drop the message
93 */
94 if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
95 return;
96
97 sg->src.s_addr = INADDR_ANY;
98 }
99
100 /* Restart join expiry timer */
101 pim_ifchannel_join_add(ifp, neigh->source_addr, upstream,
102 sg, source_flags, holdtime);
103
104 }
105
106 static void recv_prune(struct interface *ifp,
107 struct pim_neighbor *neigh,
108 uint16_t holdtime,
109 struct in_addr upstream,
110 struct prefix_sg *sg,
111 uint8_t source_flags)
112 {
113 struct pim_interface *pim_ifp = NULL;
114
115 if (PIM_DEBUG_PIM_TRACE) {
116 char up_str[INET_ADDRSTRLEN];
117 char neigh_str[INET_ADDRSTRLEN];
118 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
119 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
120 zlog_warn("%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
121 __PRETTY_FUNCTION__,
122 pim_str_sg_dump (sg),
123 source_flags & PIM_RPT_BIT_MASK,
124 source_flags & PIM_WILDCARD_BIT_MASK,
125 up_str, holdtime, neigh_str, ifp->name);
126 }
127
128 pim_ifp = ifp->info;
129 zassert(pim_ifp);
130
131 ++pim_ifp->pim_ifstat_prune_recv;
132
133 if ((source_flags & PIM_RPT_BIT_MASK) &&
134 (source_flags & PIM_WILDCARD_BIT_MASK))
135 {
136 struct pim_rpf *rp = RP (sg->grp);
137
138 // Ignoring Prune *,G's at the moment.
139 if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
140 return;
141
142 sg->src.s_addr = INADDR_ANY;
143 }
144
145 pim_ifchannel_prune(ifp, upstream, sg, source_flags, holdtime);
146
147 }
148
149 int pim_joinprune_recv(struct interface *ifp,
150 struct pim_neighbor *neigh,
151 struct in_addr src_addr,
152 uint8_t *tlv_buf, int tlv_buf_size)
153 {
154 struct prefix msg_upstream_addr;
155 uint8_t msg_num_groups;
156 uint16_t msg_holdtime;
157 int addr_offset;
158 uint8_t *buf;
159 uint8_t *pastend;
160 int remain;
161 int group;
162
163 buf = tlv_buf;
164 pastend = tlv_buf + tlv_buf_size;
165
166 /*
167 Parse ucast addr
168 */
169 addr_offset = pim_parse_addr_ucast (&msg_upstream_addr,
170 buf, pastend - buf);
171 if (addr_offset < 1) {
172 char src_str[INET_ADDRSTRLEN];
173 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
174 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
175 __PRETTY_FUNCTION__,
176 src_str, ifp->name);
177 return -1;
178 }
179 buf += addr_offset;
180
181 /*
182 Check upstream address family
183 */
184 if (msg_upstream_addr.family != AF_INET) {
185 if (PIM_DEBUG_PIM_J_P) {
186 char src_str[INET_ADDRSTRLEN];
187 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
188 zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
189 __PRETTY_FUNCTION__,
190 msg_upstream_addr.family, src_str, ifp->name);
191 }
192 return -2;
193 }
194
195 remain = pastend - buf;
196 if (remain < 4) {
197 char src_str[INET_ADDRSTRLEN];
198 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
199 zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
200 __PRETTY_FUNCTION__,
201 remain, 4, src_str, ifp->name);
202 return -4;
203 }
204
205 ++buf; /* skip reserved byte */
206 msg_num_groups = *(const uint8_t *) buf;
207 ++buf;
208 msg_holdtime = ntohs(*(const uint16_t *) buf);
209 ++buf;
210 ++buf;
211
212 if (PIM_DEBUG_PIM_J_P) {
213 char src_str[INET_ADDRSTRLEN];
214 char upstream_str[INET_ADDRSTRLEN];
215 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
216 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
217 upstream_str, sizeof(upstream_str));
218 zlog_debug ("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
219 __PRETTY_FUNCTION__,
220 upstream_str, msg_num_groups, msg_holdtime,
221 src_str, ifp->name);
222 }
223
224 /* Scan groups */
225 for (group = 0; group < msg_num_groups; ++group) {
226 struct prefix_sg sg;
227 uint8_t msg_source_flags;
228 uint16_t msg_num_joined_sources;
229 uint16_t msg_num_pruned_sources;
230 int source;
231 struct pim_ifchannel *ch = NULL;
232
233 memset (&sg, 0, sizeof (struct prefix_sg));
234 addr_offset = pim_parse_addr_group (&sg,
235 buf, pastend - buf);
236 if (addr_offset < 1) {
237 return -5;
238 }
239 buf += addr_offset;
240
241 remain = pastend - buf;
242 if (remain < 4) {
243 char src_str[INET_ADDRSTRLEN];
244 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
245 zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
246 __PRETTY_FUNCTION__,
247 remain, 4, src_str, ifp->name);
248 return -6;
249 }
250
251 msg_num_joined_sources = ntohs(*(const uint16_t *) buf);
252 buf += 2;
253 msg_num_pruned_sources = ntohs(*(const uint16_t *) buf);
254 buf += 2;
255
256 if (PIM_DEBUG_PIM_J_P) {
257 char src_str[INET_ADDRSTRLEN];
258 char upstream_str[INET_ADDRSTRLEN];
259 char group_str[INET_ADDRSTRLEN];
260 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
261 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
262 upstream_str, sizeof(upstream_str));
263 pim_inet4_dump("<grp?>", sg.grp,
264 group_str, sizeof(group_str));
265 zlog_warn("%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s",
266 __PRETTY_FUNCTION__,
267 upstream_str, group_str,
268 msg_num_joined_sources, msg_num_pruned_sources,
269 src_str, ifp->name);
270 }
271
272 /* Scan joined sources */
273 for (source = 0; source < msg_num_joined_sources; ++source) {
274 addr_offset = pim_parse_addr_source (&sg,
275 &msg_source_flags,
276 buf, pastend - buf);
277 if (addr_offset < 1) {
278 return -7;
279 }
280
281 buf += addr_offset;
282
283 recv_join(ifp, neigh, msg_holdtime,
284 msg_upstream_addr.u.prefix4,
285 &sg,
286 msg_source_flags);
287
288 if (sg.src.s_addr == INADDR_ANY)
289 {
290 ch = pim_ifchannel_find (ifp, &sg);
291 if (ch)
292 pim_ifchannel_set_star_g_join_state (ch, 0, msg_source_flags, 1);
293 }
294 }
295
296 /* Scan pruned sources */
297 for (source = 0; source < msg_num_pruned_sources; ++source) {
298 addr_offset = pim_parse_addr_source (&sg,
299 &msg_source_flags,
300 buf, pastend - buf);
301 if (addr_offset < 1) {
302 return -8;
303 }
304
305 buf += addr_offset;
306
307 recv_prune(ifp, neigh, msg_holdtime,
308 msg_upstream_addr.u.prefix4,
309 &sg,
310 msg_source_flags);
311 }
312 if (ch)
313 pim_ifchannel_set_star_g_join_state (ch, 1, msg_source_flags, 0);
314 ch = NULL;
315 } /* scan groups */
316
317 return 0;
318 }
319
320 /*
321 * J/P Message Format
322 *
323 * While the RFC clearly states that this is 32 bits wide, it
324 * is cheating. These fields:
325 * Encoded-Unicast format (6 bytes MIN)
326 * Encoded-Group format (8 bytes MIN)
327 * Encoded-Source format (8 bytes MIN)
328 * are *not* 32 bits wide.
329 *
330 * Nor does the RFC explicitly call out the size for:
331 * Reserved (1 byte)
332 * Num Groups (1 byte)
333 * Holdtime (2 bytes)
334 * Number of Joined Sources (2 bytes)
335 * Number of Pruned Sources (2 bytes)
336 *
337 * This leads to a missleading representation from casual
338 * reading and making assumptions. Be careful!
339 *
340 * 0 1 2 3
341 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
342 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
343 * |PIM Ver| Type | Reserved | Checksum |
344 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
345 * | Upstream Neighbor Address (Encoded-Unicast format) |
346 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
347 * | Reserved | Num groups | Holdtime |
348 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
349 * | Multicast Group Address 1 (Encoded-Group format) |
350 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
351 * | Number of Joined Sources | Number of Pruned Sources |
352 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
353 * | Joined Source Address 1 (Encoded-Source format) |
354 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
355 * | . |
356 * | . |
357 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
358 * | Joined Source Address n (Encoded-Source format) |
359 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
360 * | Pruned Source Address 1 (Encoded-Source format) |
361 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
362 * | . |
363 * | . |
364 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
365 * | Pruned Source Address n (Encoded-Source format) |
366 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
367 * | Multicast Group Address m (Encoded-Group format) |
368 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
369 * | Number of Joined Sources | Number of Pruned Sources |
370 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
371 * | Joined Source Address 1 (Encoded-Source format) |
372 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
373 * | . |
374 * | . |
375 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
376 * | Joined Source Address n (Encoded-Source format) |
377 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
378 * | Pruned Source Address 1 (Encoded-Source format) |
379 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
380 * | . |
381 * | . |
382 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
383 * | Pruned Source Address n (Encoded-Source format) |
384 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
385 */
386 int pim_joinprune_send(struct pim_rpf *rpf,
387 struct list *groups)
388 {
389 struct pim_jp_agg_group *group;
390 struct pim_interface *pim_ifp = NULL;
391 struct pim_jp_groups *grp = NULL;
392 struct pim_jp *msg;
393 struct listnode *node, *nnode;
394 uint8_t pim_msg[10000];
395 uint8_t *curr_ptr = pim_msg;
396 bool new_packet = true;
397 size_t packet_left = 0;
398 size_t packet_size = 0;
399 size_t group_size = 0;
400
401 on_trace (__PRETTY_FUNCTION__, rpf->source_nexthop.interface, rpf->rpf_addr.u.prefix4);
402
403 if (rpf->source_nexthop.interface)
404 pim_ifp = rpf->source_nexthop.interface->info;
405 else
406 {
407 zlog_warn ("%s: RPF interface is not present", __PRETTY_FUNCTION__);
408 return -1;
409 }
410
411 if (!pim_ifp)
412 {
413 zlog_warn ("%s: multicast not enabled on interface %s",
414 __PRETTY_FUNCTION__,
415 rpf->source_nexthop.interface->name);
416 return -1;
417 }
418
419 if (PIM_INADDR_IS_ANY(rpf->rpf_addr.u.prefix4))
420 {
421 if (PIM_DEBUG_PIM_J_P) {
422 char dst_str[INET_ADDRSTRLEN];
423 pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str));
424 zlog_debug("%s: upstream=%s is myself on interface %s",
425 __PRETTY_FUNCTION__,
426 dst_str, rpf->source_nexthop.interface->name);
427 }
428 return 0;
429 }
430
431 /*
432 RFC 4601: 4.3.1. Sending Hello Messages
433
434 Thus, if a router needs to send a Join/Prune or Assert message on
435 an interface on which it has not yet sent a Hello message with the
436 currently configured IP address, then it MUST immediately send the
437 relevant Hello message without waiting for the Hello Timer to
438 expire, followed by the Join/Prune or Assert message.
439 */
440 pim_hello_require(rpf->source_nexthop.interface);
441
442 for (ALL_LIST_ELEMENTS(groups, node, nnode, group))
443 {
444 if (new_packet)
445 {
446 msg = (struct pim_jp *)pim_msg;
447
448 memset(msg, 0, sizeof (*msg));
449
450 pim_msg_addr_encode_ipv4_ucast ((uint8_t *)&msg->addr, rpf->rpf_addr.u.prefix4);
451 msg->reserved = 0;
452 msg->holdtime = htons(PIM_JP_HOLDTIME);
453
454 new_packet = false;
455
456 grp = &msg->groups[0];
457 curr_ptr = (uint8_t *)grp;
458 packet_size = sizeof (struct pim_msg_header);
459 packet_size += sizeof (struct pim_encoded_ipv4_unicast);
460 packet_size += 4; // reserved (1) + groups (1) + holdtime (2)
461
462 packet_left = rpf->source_nexthop.interface->mtu - 24;
463 packet_left -= packet_size;
464 }
465 if (PIM_DEBUG_PIM_J_P) {
466 char dst_str[INET_ADDRSTRLEN];
467 char grp_str[INET_ADDRSTRLEN];
468 pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str));
469 pim_inet4_dump("<grp?>", group->group, grp_str, sizeof(grp_str));
470 zlog_debug("%s: sending (G)=%s to upstream=%s on interface %s",
471 __PRETTY_FUNCTION__,
472 grp_str, dst_str, rpf->source_nexthop.interface->name);
473 }
474
475 group_size = pim_msg_get_jp_group_size (group->sources);
476 if (group_size > packet_left)
477 {
478 pim_msg_build_header (pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE);
479 if (pim_msg_send(pim_ifp->pim_sock_fd,
480 pim_ifp->primary_address,
481 qpim_all_pim_routers_addr,
482 pim_msg,
483 packet_size,
484 rpf->source_nexthop.interface->name)) {
485 zlog_warn("%s: could not send PIM message on interface %s",
486 __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name);
487 }
488
489 msg = (struct pim_jp *)pim_msg;
490 memset(msg, 0, sizeof (*msg));
491
492 pim_msg_addr_encode_ipv4_ucast ((uint8_t *)&msg->addr, rpf->rpf_addr.u.prefix4);
493 msg->reserved = 0;
494 msg->holdtime = htons(PIM_JP_HOLDTIME);
495
496 new_packet = false;
497
498 grp = &msg->groups[0];
499 curr_ptr = (uint8_t *)grp;
500 packet_size = sizeof (struct pim_msg_header);
501 packet_size += sizeof (struct pim_encoded_ipv4_unicast);
502 packet_size += 4; // reserved (1) + groups (1) + holdtime (2)
503
504 packet_left = rpf->source_nexthop.interface->mtu - 24;
505 packet_left -= packet_size;
506 }
507
508 msg->num_groups++;
509 /*
510 Build PIM message
511 */
512
513 curr_ptr += group_size;
514 packet_left -= group_size;
515 packet_size += group_size;
516 pim_msg_build_jp_groups (grp, group, group_size);
517
518 pim_ifp->pim_ifstat_join_send += ntohs(grp->joins);
519 pim_ifp->pim_ifstat_prune_send += ntohs(grp->prunes);
520
521 grp = (struct pim_jp_groups *)curr_ptr;
522 if (packet_left < sizeof (struct pim_jp_groups) || msg->num_groups == 255)
523 {
524 pim_msg_build_header (pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE);
525 if (pim_msg_send(pim_ifp->pim_sock_fd,
526 pim_ifp->primary_address,
527 qpim_all_pim_routers_addr,
528 pim_msg,
529 packet_size,
530 rpf->source_nexthop.interface->name)) {
531 zlog_warn("%s: could not send PIM message on interface %s",
532 __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name);
533 }
534
535 new_packet = true;
536 }
537 }
538
539
540 if (!new_packet)
541 {
542 //msg->num_groups = htons (msg->num_groups);
543 pim_msg_build_header (pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE);
544 if (pim_msg_send(pim_ifp->pim_sock_fd,
545 pim_ifp->primary_address,
546 qpim_all_pim_routers_addr,
547 pim_msg,
548 packet_size,
549 rpf->source_nexthop.interface->name)) {
550 zlog_warn("%s: could not send PIM message on interface %s",
551 __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name);
552 }
553 }
554 return 0;
555 }