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