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