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