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