]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_join.c
Merge pull request #891 from Jafaral/portability
[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 uint8_t starg_alone = 0;
235
236 memset(&sg, 0, sizeof(struct prefix_sg));
237 addr_offset = pim_parse_addr_group(&sg, buf, pastend - buf);
238 if (addr_offset < 1) {
239 return -5;
240 }
241 buf += addr_offset;
242
243 remain = pastend - buf;
244 if (remain < 4) {
245 char src_str[INET_ADDRSTRLEN];
246 pim_inet4_dump("<src?>", src_addr, src_str,
247 sizeof(src_str));
248 zlog_warn(
249 "%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
250 __PRETTY_FUNCTION__, remain, 4, src_str,
251 ifp->name);
252 return -6;
253 }
254
255 msg_num_joined_sources = ntohs(*(const uint16_t *)buf);
256 buf += 2;
257 msg_num_pruned_sources = ntohs(*(const uint16_t *)buf);
258 buf += 2;
259
260 if (PIM_DEBUG_PIM_J_P) {
261 char src_str[INET_ADDRSTRLEN];
262 char upstream_str[INET_ADDRSTRLEN];
263 char group_str[INET_ADDRSTRLEN];
264 pim_inet4_dump("<src?>", src_addr, src_str,
265 sizeof(src_str));
266 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
267 upstream_str, sizeof(upstream_str));
268 pim_inet4_dump("<grp?>", sg.grp, group_str,
269 sizeof(group_str));
270 zlog_warn(
271 "%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s",
272 __PRETTY_FUNCTION__, upstream_str, group_str,
273 msg_num_joined_sources, msg_num_pruned_sources,
274 src_str, ifp->name);
275 }
276
277 /* Scan joined sources */
278 for (source = 0; source < msg_num_joined_sources; ++source) {
279 addr_offset = pim_parse_addr_source(
280 &sg, &msg_source_flags, buf, pastend - buf);
281 if (addr_offset < 1) {
282 return -7;
283 }
284
285 buf += addr_offset;
286
287 recv_join(ifp, neigh, msg_holdtime,
288 msg_upstream_addr.u.prefix4, &sg,
289 msg_source_flags);
290
291 if (sg.src.s_addr == INADDR_ANY) {
292 starg_alone = 1;
293 starg_ch = pim_ifchannel_find(ifp, &sg);
294 if (starg_ch)
295 pim_ifchannel_set_star_g_join_state(
296 starg_ch, 0, msg_source_flags,
297 1, starg_alone);
298 }
299 }
300
301 /* Scan pruned sources */
302 for (source = 0; source < msg_num_pruned_sources; ++source) {
303 addr_offset = pim_parse_addr_source(
304 &sg, &msg_source_flags, buf, pastend - buf);
305 if (addr_offset < 1) {
306 return -8;
307 }
308
309 sg_ch = pim_ifchannel_find(ifp, &sg);
310
311 buf += addr_offset;
312 starg_alone = 0;
313 recv_prune(ifp, neigh, msg_holdtime,
314 msg_upstream_addr.u.prefix4, &sg,
315 msg_source_flags);
316
317 /* Received SG-RPT Prune delete oif from specific S,G */
318 if (starg_ch && sg_ch
319 && (msg_source_flags & PIM_RPT_BIT_MASK)
320 && !(msg_source_flags & PIM_WILDCARD_BIT_MASK)) {
321 struct pim_upstream *up = sg_ch->upstream;
322 PIM_IF_FLAG_SET_S_G_RPT(sg_ch->flags);
323 if (up) {
324 if (PIM_DEBUG_TRACE)
325 zlog_debug(
326 "%s: SGRpt flag is set, del inherit oif from up %s",
327 __PRETTY_FUNCTION__,
328 up->sg_str);
329 pim_channel_del_oif(
330 up->channel_oil,
331 starg_ch->interface,
332 PIM_OIF_FLAG_PROTO_STAR);
333 }
334 }
335 }
336 if (starg_ch)
337 pim_ifchannel_set_star_g_join_state(
338 starg_ch, 1, msg_source_flags, 0, starg_alone);
339 starg_ch = NULL;
340 } /* scan groups */
341
342 return 0;
343 }
344
345 /*
346 * J/P Message Format
347 *
348 * While the RFC clearly states that this is 32 bits wide, it
349 * is cheating. These fields:
350 * Encoded-Unicast format (6 bytes MIN)
351 * Encoded-Group format (8 bytes MIN)
352 * Encoded-Source format (8 bytes MIN)
353 * are *not* 32 bits wide.
354 *
355 * Nor does the RFC explicitly call out the size for:
356 * Reserved (1 byte)
357 * Num Groups (1 byte)
358 * Holdtime (2 bytes)
359 * Number of Joined Sources (2 bytes)
360 * Number of Pruned Sources (2 bytes)
361 *
362 * This leads to a missleading representation from casual
363 * reading and making assumptions. Be careful!
364 *
365 * 0 1 2 3
366 * 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
367 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
368 * |PIM Ver| Type | Reserved | Checksum |
369 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
370 * | Upstream Neighbor Address (Encoded-Unicast format) |
371 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
372 * | Reserved | Num groups | Holdtime |
373 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
374 * | Multicast Group Address 1 (Encoded-Group format) |
375 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
376 * | Number of Joined Sources | Number of Pruned Sources |
377 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
378 * | Joined Source Address 1 (Encoded-Source format) |
379 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
380 * | . |
381 * | . |
382 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
383 * | Joined Source Address n (Encoded-Source format) |
384 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
385 * | Pruned Source Address 1 (Encoded-Source format) |
386 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
387 * | . |
388 * | . |
389 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
390 * | Pruned Source Address n (Encoded-Source format) |
391 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
392 * | Multicast Group Address m (Encoded-Group format) |
393 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
394 * | Number of Joined Sources | Number of Pruned Sources |
395 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
396 * | Joined Source Address 1 (Encoded-Source format) |
397 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
398 * | . |
399 * | . |
400 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
401 * | Joined Source Address n (Encoded-Source format) |
402 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
403 * | Pruned Source Address 1 (Encoded-Source format) |
404 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
405 * | . |
406 * | . |
407 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
408 * | Pruned Source Address n (Encoded-Source format) |
409 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
410 */
411 int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
412 {
413 struct pim_jp_agg_group *group;
414 struct pim_interface *pim_ifp = NULL;
415 struct pim_jp_groups *grp = NULL;
416 struct pim_jp *msg;
417 struct listnode *node, *nnode;
418 uint8_t pim_msg[10000];
419 uint8_t *curr_ptr = pim_msg;
420 bool new_packet = true;
421 size_t packet_left = 0;
422 size_t packet_size = 0;
423 size_t group_size = 0;
424
425 on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface,
426 rpf->rpf_addr.u.prefix4);
427
428 if (rpf->source_nexthop.interface)
429 pim_ifp = rpf->source_nexthop.interface->info;
430 else {
431 zlog_warn("%s: RPF interface is not present",
432 __PRETTY_FUNCTION__);
433 return -1;
434 }
435
436 if (!pim_ifp) {
437 zlog_warn("%s: multicast not enabled on interface %s",
438 __PRETTY_FUNCTION__,
439 rpf->source_nexthop.interface->name);
440 return -1;
441 }
442
443 if (PIM_INADDR_IS_ANY(rpf->rpf_addr.u.prefix4)) {
444 if (PIM_DEBUG_PIM_J_P) {
445 char dst_str[INET_ADDRSTRLEN];
446 pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4,
447 dst_str, sizeof(dst_str));
448 zlog_debug("%s: upstream=%s is myself on interface %s",
449 __PRETTY_FUNCTION__, dst_str,
450 rpf->source_nexthop.interface->name);
451 }
452 return 0;
453 }
454
455 /*
456 RFC 4601: 4.3.1. Sending Hello Messages
457
458 Thus, if a router needs to send a Join/Prune or Assert message on
459 an interface on which it has not yet sent a Hello message with the
460 currently configured IP address, then it MUST immediately send the
461 relevant Hello message without waiting for the Hello Timer to
462 expire, followed by the Join/Prune or Assert message.
463 */
464 pim_hello_require(rpf->source_nexthop.interface);
465
466 for (ALL_LIST_ELEMENTS(groups, node, nnode, group)) {
467 if (new_packet) {
468 msg = (struct pim_jp *)pim_msg;
469
470 memset(msg, 0, sizeof(*msg));
471
472 pim_msg_addr_encode_ipv4_ucast((uint8_t *)&msg->addr,
473 rpf->rpf_addr.u.prefix4);
474 msg->reserved = 0;
475 msg->holdtime = htons(PIM_JP_HOLDTIME);
476
477 new_packet = false;
478
479 grp = &msg->groups[0];
480 curr_ptr = (uint8_t *)grp;
481 packet_size = sizeof(struct pim_msg_header);
482 packet_size += sizeof(struct pim_encoded_ipv4_unicast);
483 packet_size +=
484 4; // reserved (1) + groups (1) + holdtime (2)
485
486 packet_left = rpf->source_nexthop.interface->mtu - 24;
487 packet_left -= packet_size;
488 }
489 if (PIM_DEBUG_PIM_J_P) {
490 char dst_str[INET_ADDRSTRLEN];
491 char grp_str[INET_ADDRSTRLEN];
492 pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4,
493 dst_str, sizeof(dst_str));
494 pim_inet4_dump("<grp?>", group->group, grp_str,
495 sizeof(grp_str));
496 zlog_debug(
497 "%s: sending (G)=%s to upstream=%s on interface %s",
498 __PRETTY_FUNCTION__, grp_str, dst_str,
499 rpf->source_nexthop.interface->name);
500 }
501
502 group_size = pim_msg_get_jp_group_size(group->sources);
503 if (group_size > packet_left) {
504 pim_msg_build_header(pim_msg, packet_size,
505 PIM_MSG_TYPE_JOIN_PRUNE);
506 if (pim_msg_send(pim_ifp->pim_sock_fd,
507 pim_ifp->primary_address,
508 qpim_all_pim_routers_addr, pim_msg,
509 packet_size,
510 rpf->source_nexthop.interface->name)) {
511 zlog_warn(
512 "%s: could not send PIM message on interface %s",
513 __PRETTY_FUNCTION__,
514 rpf->source_nexthop.interface->name);
515 }
516
517 msg = (struct pim_jp *)pim_msg;
518 memset(msg, 0, sizeof(*msg));
519
520 pim_msg_addr_encode_ipv4_ucast((uint8_t *)&msg->addr,
521 rpf->rpf_addr.u.prefix4);
522 msg->reserved = 0;
523 msg->holdtime = htons(PIM_JP_HOLDTIME);
524
525 new_packet = false;
526
527 grp = &msg->groups[0];
528 curr_ptr = (uint8_t *)grp;
529 packet_size = sizeof(struct pim_msg_header);
530 packet_size += sizeof(struct pim_encoded_ipv4_unicast);
531 packet_size +=
532 4; // reserved (1) + groups (1) + holdtime (2)
533
534 packet_left = rpf->source_nexthop.interface->mtu - 24;
535 packet_left -= packet_size;
536 }
537
538 msg->num_groups++;
539 /*
540 Build PIM message
541 */
542
543 curr_ptr += group_size;
544 packet_left -= group_size;
545 packet_size += group_size;
546 pim_msg_build_jp_groups(grp, group, group_size);
547
548 pim_ifp->pim_ifstat_join_send += ntohs(grp->joins);
549 pim_ifp->pim_ifstat_prune_send += ntohs(grp->prunes);
550
551 if (PIM_DEBUG_PIM_TRACE)
552 zlog_debug(
553 "%s: interface %s num_joins %u num_prunes %u",
554 __PRETTY_FUNCTION__,
555 rpf->source_nexthop.interface->name,
556 ntohs(grp->joins), ntohs(grp->prunes));
557
558 grp = (struct pim_jp_groups *)curr_ptr;
559 if (packet_left < sizeof(struct pim_jp_groups)
560 || msg->num_groups == 255) {
561 pim_msg_build_header(pim_msg, packet_size,
562 PIM_MSG_TYPE_JOIN_PRUNE);
563 if (pim_msg_send(pim_ifp->pim_sock_fd,
564 pim_ifp->primary_address,
565 qpim_all_pim_routers_addr, pim_msg,
566 packet_size,
567 rpf->source_nexthop.interface->name)) {
568 zlog_warn(
569 "%s: could not send PIM message on interface %s",
570 __PRETTY_FUNCTION__,
571 rpf->source_nexthop.interface->name);
572 }
573
574 new_packet = true;
575 }
576 }
577
578
579 if (!new_packet) {
580 // msg->num_groups = htons (msg->num_groups);
581 pim_msg_build_header(pim_msg, packet_size,
582 PIM_MSG_TYPE_JOIN_PRUNE);
583 if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
584 qpim_all_pim_routers_addr, pim_msg,
585 packet_size,
586 rpf->source_nexthop.interface->name)) {
587 zlog_warn(
588 "%s: could not send PIM message on interface %s",
589 __PRETTY_FUNCTION__,
590 rpf->source_nexthop.interface->name);
591 }
592 }
593 return 0;
594 }