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