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