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