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