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