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