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