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