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