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