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