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