]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_join.c
pimd: Handle rpf_addr in join/prune processing
[mirror_frr.git] / pimd / pim_join.c
CommitLineData
38c848c9
DS
1
2
12e41d03 3/*
896014f4
DL
4 * PIM for Quagga
5 * Copyright (C) 2008 Everton da Silva Marques
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
12e41d03
DL
21
22#include <zebra.h>
23
24#include "log.h"
25#include "prefix.h"
744d91b3 26#include "if.h"
dfe43e25
DW
27#include "vty.h"
28#include "plist.h"
12e41d03
DL
29
30#include "pimd.h"
993e3d8e 31#include "pim_instance.h"
12e41d03
DL
32#include "pim_str.h"
33#include "pim_tlv.h"
34#include "pim_msg.h"
35#include "pim_pim.h"
36#include "pim_join.h"
3667b0bc 37#include "pim_oil.h"
12e41d03
DL
38#include "pim_iface.h"
39#include "pim_hello.h"
40#include "pim_ifchannel.h"
6c629103
DS
41#include "pim_rpf.h"
42#include "pim_rp.h"
982bff89 43#include "pim_jp_agg.h"
b0f525a8 44#include "pim_util.h"
34abbcc4 45#include "pim_ssm.h"
12e41d03 46
042a7541 47static void on_trace(const char *label, struct interface *ifp, pim_addr src)
12e41d03 48{
042a7541
DL
49 if (PIM_DEBUG_PIM_TRACE)
50 zlog_debug("%s: from %pPA on %s", label, &src, ifp->name);
12e41d03
DL
51}
52
d62a17ae 53static void recv_join(struct interface *ifp, struct pim_neighbor *neigh,
01adb431
DL
54 uint16_t holdtime, pim_addr upstream, pim_sgaddr *sg,
55 uint8_t source_flags)
12e41d03 56{
d62a17ae 57 struct pim_interface *pim_ifp = NULL;
58
01adb431 59 if (PIM_DEBUG_PIM_TRACE)
9bb93fa0 60 zlog_debug(
01adb431 61 "%s: join (S,G)=%pSG rpt=%d wc=%d upstream=%pPAs holdtime=%d from %pPA on %s",
9bb93fa0 62 __func__, sg, !!(source_flags & PIM_RPT_BIT_MASK),
01adb431 63 !!(source_flags & PIM_WILDCARD_BIT_MASK), &upstream,
9bb93fa0 64 holdtime, &neigh->source_addr, ifp->name);
d62a17ae 65
66 pim_ifp = ifp->info;
df5dfb77 67 assert(pim_ifp);
d62a17ae 68
69 ++pim_ifp->pim_ifstat_join_recv;
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)) {
fec883d9 77 struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp);
c631920c 78 pim_addr rpf_addr;
d62a17ae 79
b1945363 80 if (!rp) {
6fff2cc6
DL
81 zlog_warn("%s: Lookup of RP failed for %pSG", __func__,
82 sg);
b1945363
DS
83 return;
84 }
d62a17ae 85 /*
86 * If the RP sent in the message is not
87 * our RP for the group, drop the message
88 */
fc9f6f88 89 rpf_addr = rp->rpf_addr;
c631920c 90 if (pim_addr_cmp(sg->src, rpf_addr)) {
15569c58 91 zlog_warn(
c631920c
DL
92 "%s: Specified RP(%pPAs) in join is different than our configured RP(%pPAs)",
93 __func__, &sg->src, &rpf_addr);
d62a17ae 94 return;
a57103e9 95 }
d62a17ae 96
34abbcc4
SG
97 if (pim_is_grp_ssm(pim_ifp->pim, sg->grp)) {
98 zlog_warn(
6d7bf748 99 "%s: Specified Group(%pPA) in join is now in SSM, not allowed to create PIM state",
38c848c9 100 __func__, &sg->grp);
34abbcc4
SG
101 return;
102 }
103
bca160c6 104 sg->src = PIMADDR_ANY;
d62a17ae 105 }
106
107 /* Restart join expiry timer */
108 pim_ifchannel_join_add(ifp, neigh->source_addr, upstream, sg,
109 source_flags, holdtime);
12e41d03
DL
110}
111
d62a17ae 112static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh,
01adb431
DL
113 uint16_t holdtime, pim_addr upstream, pim_sgaddr *sg,
114 uint8_t source_flags)
12e41d03 115{
d62a17ae 116 struct pim_interface *pim_ifp = NULL;
117
01adb431 118 if (PIM_DEBUG_PIM_TRACE)
9bb93fa0 119 zlog_debug(
01adb431 120 "%s: prune (S,G)=%pSG rpt=%d wc=%d upstream=%pPAs holdtime=%d from %pPA on %s",
9bb93fa0 121 __func__, sg, source_flags & PIM_RPT_BIT_MASK,
01adb431
DL
122 source_flags & PIM_WILDCARD_BIT_MASK, &upstream,
123 holdtime, &neigh->source_addr, ifp->name);
d62a17ae 124
125 pim_ifp = ifp->info;
df5dfb77 126 assert(pim_ifp);
d62a17ae 127
128 ++pim_ifp->pim_ifstat_prune_recv;
129
130 if ((source_flags & PIM_RPT_BIT_MASK)
131 && (source_flags & PIM_WILDCARD_BIT_MASK)) {
5c777da8 132 /*
133 * RFC 4601 Section 4.5.2:
134 * Received Prune(*,G) messages are processed even if the
135 * RP in the message does not match RP(G).
136 */
8e8be741
DL
137 if (PIM_DEBUG_PIM_TRACE)
138 zlog_debug("%s: Prune received with RP(%pPAs) for %pSG",
139 __func__, &sg->src, sg);
d62a17ae 140
bca160c6 141 sg->src = PIMADDR_ANY;
d62a17ae 142 }
143
144 pim_ifchannel_prune(ifp, upstream, sg, source_flags, holdtime);
12e41d03
DL
145}
146
d62a17ae 147int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
17280eee 148 pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size)
12e41d03 149{
0d360092
DL
150 pim_addr msg_upstream_addr;
151 bool wrong_af = false;
b0f525a8 152 struct pim_interface *pim_ifp;
d62a17ae 153 uint8_t msg_num_groups;
154 uint16_t msg_holdtime;
155 int addr_offset;
156 uint8_t *buf;
157 uint8_t *pastend;
158 int remain;
159 int group;
fa8c500f
SP
160 struct pim_ifchannel *child = NULL;
161 struct listnode *ch_node, *nch_node;
d62a17ae 162
163 buf = tlv_buf;
164 pastend = tlv_buf + tlv_buf_size;
b0f525a8 165 pim_ifp = ifp->info;
d62a17ae 166
b9695c6d 167 if (pim_ifp->pim_passive_enable) {
168 if (PIM_DEBUG_PIM_PACKETS)
169 zlog_debug(
170 "skip receiving PIM message on passive interface %s",
171 ifp->name);
172 return 0;
173 }
174
d62a17ae 175 /*
176 Parse ucast addr
177 */
0d360092
DL
178 addr_offset = pim_parse_addr_ucast(&msg_upstream_addr, buf,
179 pastend - buf, &wrong_af);
d62a17ae 180 if (addr_offset < 1) {
17280eee
MR
181 zlog_warn("%s: pim_parse_addr_ucast() failure: from %pPA on %s",
182 __func__, &src_addr, ifp->name);
d62a17ae 183 return -1;
184 }
185 buf += addr_offset;
186
187 /*
188 Check upstream address family
189 */
0d360092 190 if (wrong_af) {
15569c58 191 zlog_warn(
17280eee
MR
192 "%s: ignoring join/prune directed to unexpected addr family from %pPA on %s",
193 __func__, &src_addr, ifp->name);
d62a17ae 194 return -2;
195 }
196
197 remain = pastend - buf;
198 if (remain < 4) {
d62a17ae 199 zlog_warn(
17280eee
MR
200 "%s: short join/prune message buffer for group list: size=%d minimum=%d from %pPA on %s",
201 __func__, remain, 4, &src_addr, ifp->name);
d62a17ae 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
17280eee 212 if (PIM_DEBUG_PIM_J_P)
d62a17ae 213 zlog_debug(
17280eee 214 "%s: join/prune upstream=%pPAs groups=%d holdtime=%d from %pPA on %s",
0d360092 215 __func__, &msg_upstream_addr, msg_num_groups,
17280eee 216 msg_holdtime, &src_addr, ifp->name);
d62a17ae 217
218 /* Scan groups */
219 for (group = 0; group < msg_num_groups; ++group) {
6fff2cc6 220 pim_sgaddr sg;
d62a17ae 221 uint8_t msg_source_flags;
222 uint16_t msg_num_joined_sources;
223 uint16_t msg_num_pruned_sources;
224 int source;
225 struct pim_ifchannel *starg_ch = NULL, *sg_ch = NULL;
b0f525a8 226 bool filtered = false;
d62a17ae 227
6fff2cc6 228 memset(&sg, 0, sizeof(sg));
d62a17ae 229 addr_offset = pim_parse_addr_group(&sg, buf, pastend - buf);
230 if (addr_offset < 1) {
231 return -5;
232 }
233 buf += addr_offset;
234
235 remain = pastend - buf;
236 if (remain < 4) {
d62a17ae 237 zlog_warn(
17280eee
MR
238 "%s: short join/prune buffer for source list: size=%d minimum=%d from %pPA on %s",
239 __func__, remain, 4, &src_addr, ifp->name);
d62a17ae 240 return -6;
241 }
242
243 msg_num_joined_sources = ntohs(*(const uint16_t *)buf);
244 buf += 2;
245 msg_num_pruned_sources = ntohs(*(const uint16_t *)buf);
246 buf += 2;
247
17280eee 248 if (PIM_DEBUG_PIM_J_P)
fb9670aa 249 zlog_debug(
17280eee 250 "%s: join/prune upstream=%pPAs group=%pPA/32 join_src=%d prune_src=%d from %pPA on %s",
0d360092 251 __func__, &msg_upstream_addr, &sg.grp,
d62a17ae 252 msg_num_joined_sources, msg_num_pruned_sources,
17280eee 253 &src_addr, ifp->name);
d62a17ae 254
b0f525a8
QY
255 /* boundary check */
256 filtered = pim_is_group_filtered(pim_ifp, &sg.grp);
257
d62a17ae 258 /* Scan joined sources */
259 for (source = 0; source < msg_num_joined_sources; ++source) {
260 addr_offset = pim_parse_addr_source(
261 &sg, &msg_source_flags, buf, pastend - buf);
262 if (addr_offset < 1) {
263 return -7;
264 }
265
266 buf += addr_offset;
267
b0f525a8
QY
268 /* if we are filtering this group, skip the join */
269 if (filtered)
270 continue;
271
0d360092
DL
272 recv_join(ifp, neigh, msg_holdtime, msg_upstream_addr,
273 &sg, msg_source_flags);
d62a17ae 274
2a27f13b 275 if (pim_addr_is_any(sg.src)) {
d62a17ae 276 starg_ch = pim_ifchannel_find(ifp, &sg);
277 if (starg_ch)
278 pim_ifchannel_set_star_g_join_state(
c206937b 279 starg_ch, 0, 1);
d62a17ae 280 }
281 }
282
283 /* Scan pruned sources */
284 for (source = 0; source < msg_num_pruned_sources; ++source) {
285 addr_offset = pim_parse_addr_source(
286 &sg, &msg_source_flags, buf, pastend - buf);
287 if (addr_offset < 1) {
288 return -8;
289 }
290
d62a17ae 291 buf += addr_offset;
b0f525a8
QY
292
293 /* if we are filtering this group, skip the prune */
294 if (filtered)
295 continue;
296
0d360092
DL
297 recv_prune(ifp, neigh, msg_holdtime, msg_upstream_addr,
298 &sg, msg_source_flags);
8e7a4c6e
DS
299 /*
300 * So if we are receiving a S,G,RPT prune
301 * before we have any data for that S,G
302 * We need to retrieve the sg_ch after
303 * we parse the prune.
304 */
305 sg_ch = pim_ifchannel_find(ifp, &sg);
306
fa8c500f
SP
307 if (!sg_ch)
308 continue;
309
310 /* (*,G) prune received */
311 for (ALL_LIST_ELEMENTS(sg_ch->sources, ch_node,
312 nch_node, child)) {
313 if (PIM_IF_FLAG_TEST_S_G_RPT(child->flags)) {
314 if (child->ifjoin_state
315 == PIM_IFJOIN_PRUNE_PENDING_TMP)
316 THREAD_OFF(
317 child->t_ifjoin_prune_pending_timer);
99f9518b 318 THREAD_OFF(
319 child->t_ifjoin_expiry_timer);
fa8c500f
SP
320 PIM_IF_FLAG_UNSET_S_G_RPT(child->flags);
321 child->ifjoin_state = PIM_IFJOIN_NOINFO;
99f9518b 322 delete_on_noinfo(child);
fa8c500f
SP
323 }
324 }
325
d62a17ae 326 /* Received SG-RPT Prune delete oif from specific S,G */
fa8c500f 327 if (starg_ch && (msg_source_flags & PIM_RPT_BIT_MASK)
d62a17ae 328 && !(msg_source_flags & PIM_WILDCARD_BIT_MASK)) {
329 struct pim_upstream *up = sg_ch->upstream;
330 PIM_IF_FLAG_SET_S_G_RPT(sg_ch->flags);
331 if (up) {
23fc858a 332 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 333 zlog_debug(
334 "%s: SGRpt flag is set, del inherit oif from up %s",
15569c58 335 __func__, up->sg_str);
1537a668 336 pim_channel_del_inherited_oif(
d62a17ae 337 up->channel_oil,
338 starg_ch->interface,
1b249e70 339 __func__);
d62a17ae 340 }
341 }
342 }
b0f525a8 343 if (starg_ch && !filtered)
c206937b 344 pim_ifchannel_set_star_g_join_state(starg_ch, 1, 0);
d62a17ae 345 starg_ch = NULL;
346 } /* scan groups */
347
348 return 0;
12e41d03
DL
349}
350
982bff89
DS
351/*
352 * J/P Message Format
353 *
354 * While the RFC clearly states that this is 32 bits wide, it
355 * is cheating. These fields:
356 * Encoded-Unicast format (6 bytes MIN)
357 * Encoded-Group format (8 bytes MIN)
358 * Encoded-Source format (8 bytes MIN)
359 * are *not* 32 bits wide.
360 *
361 * Nor does the RFC explicitly call out the size for:
362 * Reserved (1 byte)
363 * Num Groups (1 byte)
364 * Holdtime (2 bytes)
365 * Number of Joined Sources (2 bytes)
366 * Number of Pruned Sources (2 bytes)
367 *
368 * This leads to a missleading representation from casual
369 * reading and making assumptions. Be careful!
370 *
371 * 0 1 2 3
372 * 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
373 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
374 * |PIM Ver| Type | Reserved | Checksum |
375 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
376 * | Upstream Neighbor Address (Encoded-Unicast format) |
377 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
378 * | Reserved | Num groups | Holdtime |
379 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
380 * | Multicast Group Address 1 (Encoded-Group format) |
381 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
382 * | Number of Joined Sources | Number of Pruned Sources |
383 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
384 * | Joined Source Address 1 (Encoded-Source format) |
385 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
386 * | . |
387 * | . |
388 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
389 * | Joined Source Address n (Encoded-Source format) |
390 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
391 * | Pruned Source Address 1 (Encoded-Source format) |
392 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
393 * | . |
394 * | . |
395 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
396 * | Pruned Source Address n (Encoded-Source format) |
397 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
398 * | Multicast Group Address m (Encoded-Group format) |
399 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
400 * | Number of Joined Sources | Number of Pruned Sources |
401 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
402 * | Joined Source Address 1 (Encoded-Source format) |
403 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
404 * | . |
405 * | . |
406 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
407 * | Joined Source Address n (Encoded-Source format) |
408 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
409 * | Pruned Source Address 1 (Encoded-Source format) |
410 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
411 * | . |
412 * | . |
413 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
414 * | Pruned Source Address n (Encoded-Source format) |
415 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
416 */
d62a17ae 417int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
12e41d03 418{
d62a17ae 419 struct pim_jp_agg_group *group;
420 struct pim_interface *pim_ifp = NULL;
421 struct pim_jp_groups *grp = NULL;
a97986ff 422 struct pim_jp *msg = NULL;
d62a17ae 423 struct listnode *node, *nnode;
424 uint8_t pim_msg[10000];
425 uint8_t *curr_ptr = pim_msg;
426 bool new_packet = true;
427 size_t packet_left = 0;
428 size_t packet_size = 0;
429 size_t group_size = 0;
430
d62a17ae 431 if (rpf->source_nexthop.interface)
432 pim_ifp = rpf->source_nexthop.interface->info;
433 else {
5e81f5dd 434 zlog_warn("%s: RPF interface is not present", __func__);
d62a17ae 435 return -1;
436 }
437
042a7541 438
fc9f6f88 439 on_trace(__func__, rpf->source_nexthop.interface, rpf->rpf_addr);
957d93ea 440
d62a17ae 441 if (!pim_ifp) {
5e81f5dd 442 zlog_warn("%s: multicast not enabled on interface %s", __func__,
d62a17ae 443 rpf->source_nexthop.interface->name);
444 return -1;
445 }
446
fc9f6f88 447 if (pim_addr_is_any(rpf->rpf_addr)) {
042a7541
DL
448 if (PIM_DEBUG_PIM_J_P)
449 zlog_debug(
450 "%s: upstream=%pPA is myself on interface %s",
fc9f6f88 451 __func__, &rpf->rpf_addr,
042a7541 452 rpf->source_nexthop.interface->name);
d62a17ae 453 return 0;
454 }
455
456 /*
457 RFC 4601: 4.3.1. Sending Hello Messages
458
459 Thus, if a router needs to send a Join/Prune or Assert message on
460 an interface on which it has not yet sent a Hello message with the
461 currently configured IP address, then it MUST immediately send the
462 relevant Hello message without waiting for the Hello Timer to
463 expire, followed by the Join/Prune or Assert message.
464 */
465 pim_hello_require(rpf->source_nexthop.interface);
466
467 for (ALL_LIST_ELEMENTS(groups, node, nnode, group)) {
468 if (new_packet) {
469 msg = (struct pim_jp *)pim_msg;
470
471 memset(msg, 0, sizeof(*msg));
472
042a7541 473 pim_msg_addr_encode_ucast((uint8_t *)&msg->addr,
fc9f6f88 474 rpf->rpf_addr);
d62a17ae 475 msg->reserved = 0;
476 msg->holdtime = htons(PIM_JP_HOLDTIME);
477
478 new_packet = false;
479
480 grp = &msg->groups[0];
481 curr_ptr = (uint8_t *)grp;
482 packet_size = sizeof(struct pim_msg_header);
16763d77 483 packet_size += sizeof(pim_encoded_unicast);
d62a17ae 484 packet_size +=
485 4; // reserved (1) + groups (1) + holdtime (2)
486
487 packet_left = rpf->source_nexthop.interface->mtu - 24;
488 packet_left -= packet_size;
489 }
042a7541 490 if (PIM_DEBUG_PIM_J_P)
d62a17ae 491 zlog_debug(
042a7541 492 "%s: sending (G)=%pPAs to upstream=%pPA on interface %s",
fc9f6f88 493 __func__, &group->group, &rpf->rpf_addr,
d62a17ae 494 rpf->source_nexthop.interface->name);
d62a17ae 495
496 group_size = pim_msg_get_jp_group_size(group->sources);
497 if (group_size > packet_left) {
145e4c38
DL
498 pim_msg_build_header(pim_ifp->primary_address,
499 qpim_all_pim_routers_addr, pim_msg,
500 packet_size,
d57a8bbf 501 PIM_MSG_TYPE_JOIN_PRUNE, false);
d62a17ae 502 if (pim_msg_send(pim_ifp->pim_sock_fd,
503 pim_ifp->primary_address,
504 qpim_all_pim_routers_addr, pim_msg,
505 packet_size,
22870562 506 rpf->source_nexthop.interface)) {
d62a17ae 507 zlog_warn(
508 "%s: could not send PIM message on interface %s",
5e81f5dd 509 __func__,
d62a17ae 510 rpf->source_nexthop.interface->name);
511 }
512
513 msg = (struct pim_jp *)pim_msg;
514 memset(msg, 0, sizeof(*msg));
515
042a7541 516 pim_msg_addr_encode_ucast((uint8_t *)&msg->addr,
fc9f6f88 517 rpf->rpf_addr);
d62a17ae 518 msg->reserved = 0;
519 msg->holdtime = htons(PIM_JP_HOLDTIME);
520
521 new_packet = false;
522
523 grp = &msg->groups[0];
524 curr_ptr = (uint8_t *)grp;
525 packet_size = sizeof(struct pim_msg_header);
16763d77 526 packet_size += sizeof(pim_encoded_unicast);
d62a17ae 527 packet_size +=
528 4; // reserved (1) + groups (1) + holdtime (2)
529
530 packet_left = rpf->source_nexthop.interface->mtu - 24;
531 packet_left -= packet_size;
532 }
533
534 msg->num_groups++;
535 /*
536 Build PIM message
537 */
538
539 curr_ptr += group_size;
540 packet_left -= group_size;
541 packet_size += group_size;
542 pim_msg_build_jp_groups(grp, group, group_size);
543
22870562 544 if (!pim_ifp->pim_passive_enable) {
545 pim_ifp->pim_ifstat_join_send += ntohs(grp->joins);
546 pim_ifp->pim_ifstat_prune_send += ntohs(grp->prunes);
547 }
d62a17ae 548
549 if (PIM_DEBUG_PIM_TRACE)
550 zlog_debug(
551 "%s: interface %s num_joins %u num_prunes %u",
5e81f5dd 552 __func__, rpf->source_nexthop.interface->name,
d62a17ae 553 ntohs(grp->joins), ntohs(grp->prunes));
554
555 grp = (struct pim_jp_groups *)curr_ptr;
556 if (packet_left < sizeof(struct pim_jp_groups)
557 || msg->num_groups == 255) {
145e4c38
DL
558 pim_msg_build_header(pim_ifp->primary_address,
559 qpim_all_pim_routers_addr, pim_msg,
560 packet_size,
d57a8bbf 561 PIM_MSG_TYPE_JOIN_PRUNE, false);
d62a17ae 562 if (pim_msg_send(pim_ifp->pim_sock_fd,
563 pim_ifp->primary_address,
564 qpim_all_pim_routers_addr, pim_msg,
565 packet_size,
22870562 566 rpf->source_nexthop.interface)) {
d62a17ae 567 zlog_warn(
568 "%s: could not send PIM message on interface %s",
5e81f5dd 569 __func__,
d62a17ae 570 rpf->source_nexthop.interface->name);
571 }
572
573 new_packet = true;
574 }
575 }
576
577
578 if (!new_packet) {
579 // msg->num_groups = htons (msg->num_groups);
145e4c38
DL
580 pim_msg_build_header(
581 pim_ifp->primary_address, qpim_all_pim_routers_addr,
582 pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE, false);
d62a17ae 583 if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
584 qpim_all_pim_routers_addr, pim_msg,
22870562 585 packet_size, rpf->source_nexthop.interface)) {
d62a17ae 586 zlog_warn(
587 "%s: could not send PIM message on interface %s",
5e81f5dd 588 __func__, rpf->source_nexthop.interface->name);
d62a17ae 589 }
590 }
591 return 0;
12e41d03 592}