]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_join.c
*: Use proper semantics for turning off thread
[mirror_frr.git] / pimd / pim_join.c
CommitLineData
12e41d03 1/*
896014f4
DL
2 * PIM for Quagga
3 * Copyright (C) 2008 Everton da Silva Marques
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
12e41d03
DL
19
20#include <zebra.h>
21
22#include "log.h"
23#include "prefix.h"
744d91b3 24#include "if.h"
dfe43e25
DW
25#include "vty.h"
26#include "plist.h"
12e41d03
DL
27
28#include "pimd.h"
29#include "pim_str.h"
30#include "pim_tlv.h"
31#include "pim_msg.h"
32#include "pim_pim.h"
33#include "pim_join.h"
3667b0bc 34#include "pim_oil.h"
12e41d03
DL
35#include "pim_iface.h"
36#include "pim_hello.h"
37#include "pim_ifchannel.h"
6c629103
DS
38#include "pim_rpf.h"
39#include "pim_rp.h"
982bff89 40#include "pim_jp_agg.h"
b0f525a8 41#include "pim_util.h"
12e41d03 42
d62a17ae 43static void on_trace(const char *label, struct interface *ifp,
44 struct in_addr src)
12e41d03 45{
d62a17ae 46 if (PIM_DEBUG_PIM_TRACE) {
47 char src_str[INET_ADDRSTRLEN];
48 pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
49 zlog_debug("%s: from %s on %s", label, src_str, ifp->name);
50 }
12e41d03
DL
51}
52
d62a17ae 53static void recv_join(struct interface *ifp, struct pim_neighbor *neigh,
54 uint16_t holdtime, struct in_addr upstream,
55 struct prefix_sg *sg, uint8_t source_flags)
12e41d03 56{
d62a17ae 57 struct pim_interface *pim_ifp = NULL;
58
59 if (PIM_DEBUG_PIM_TRACE) {
60 char up_str[INET_ADDRSTRLEN];
61 char neigh_str[INET_ADDRSTRLEN];
62 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
63 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str,
64 sizeof(neigh_str));
fb9670aa 65 zlog_debug(
d62a17ae 66 "%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
15569c58 67 __func__, pim_str_sg_dump(sg),
a57103e9
DS
68 !!(source_flags & PIM_RPT_BIT_MASK),
69 !!(source_flags & PIM_WILDCARD_BIT_MASK), up_str,
70 holdtime, neigh_str, ifp->name);
d62a17ae 71 }
72
73 pim_ifp = ifp->info;
74 zassert(pim_ifp);
75
76 ++pim_ifp->pim_ifstat_join_recv;
77
78 /*
79 * If the RPT and WC are set it's a (*,G)
80 * and the source is the RP
81 */
82 if ((source_flags & PIM_RPT_BIT_MASK)
83 && (source_flags & PIM_WILDCARD_BIT_MASK)) {
fec883d9 84 struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp);
d62a17ae 85
b1945363 86 if (!rp) {
15569c58
DA
87 zlog_warn("%s: Lookup of RP failed for %pSG4", __func__,
88 sg);
b1945363
DS
89 return;
90 }
d62a17ae 91 /*
92 * If the RP sent in the message is not
93 * our RP for the group, drop the message
94 */
a57103e9
DS
95 if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr) {
96 char received_rp[INET_ADDRSTRLEN];
97 char local_rp[INET_ADDRSTRLEN];
98 pim_inet4_dump("<received?>", sg->src, received_rp,
99 sizeof(received_rp));
100 pim_inet4_dump("<local?>", rp->rpf_addr.u.prefix4,
101 local_rp, sizeof(local_rp));
15569c58
DA
102 zlog_warn(
103 "%s: Specified RP(%s) in join is different than our configured RP(%s)",
104 __func__, received_rp, local_rp);
d62a17ae 105 return;
a57103e9 106 }
d62a17ae 107
108 sg->src.s_addr = INADDR_ANY;
109 }
110
111 /* Restart join expiry timer */
112 pim_ifchannel_join_add(ifp, neigh->source_addr, upstream, sg,
113 source_flags, holdtime);
12e41d03
DL
114}
115
d62a17ae 116static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh,
117 uint16_t holdtime, struct in_addr upstream,
118 struct prefix_sg *sg, uint8_t source_flags)
12e41d03 119{
d62a17ae 120 struct pim_interface *pim_ifp = NULL;
121
122 if (PIM_DEBUG_PIM_TRACE) {
123 char up_str[INET_ADDRSTRLEN];
124 char neigh_str[INET_ADDRSTRLEN];
125 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
126 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str,
127 sizeof(neigh_str));
fb9670aa 128 zlog_debug(
d62a17ae 129 "%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
15569c58 130 __func__, pim_str_sg_dump(sg),
d62a17ae 131 source_flags & PIM_RPT_BIT_MASK,
132 source_flags & PIM_WILDCARD_BIT_MASK, up_str, holdtime,
133 neigh_str, ifp->name);
134 }
135
136 pim_ifp = ifp->info;
137 zassert(pim_ifp);
138
139 ++pim_ifp->pim_ifstat_prune_recv;
140
141 if ((source_flags & PIM_RPT_BIT_MASK)
142 && (source_flags & PIM_WILDCARD_BIT_MASK)) {
5c777da8 143 /*
144 * RFC 4601 Section 4.5.2:
145 * Received Prune(*,G) messages are processed even if the
146 * RP in the message does not match RP(G).
147 */
148 if (PIM_DEBUG_PIM_TRACE) {
149 char received_rp[INET_ADDRSTRLEN];
d62a17ae 150
5c777da8 151 pim_inet4_dump("<received?>", sg->src, received_rp,
152 sizeof(received_rp));
153 zlog_debug("%s: Prune received with RP(%s) for %pSG4",
154 __func__, received_rp, sg);
b1945363 155 }
d62a17ae 156
157 sg->src.s_addr = INADDR_ANY;
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{
d62a17ae 167 struct prefix msg_upstream_addr;
b0f525a8 168 struct pim_interface *pim_ifp;
d62a17ae 169 uint8_t msg_num_groups;
170 uint16_t msg_holdtime;
171 int addr_offset;
172 uint8_t *buf;
173 uint8_t *pastend;
174 int remain;
175 int group;
176
177 buf = tlv_buf;
178 pastend = tlv_buf + tlv_buf_size;
b0f525a8 179 pim_ifp = ifp->info;
d62a17ae 180
181 /*
182 Parse ucast addr
183 */
184 addr_offset =
185 pim_parse_addr_ucast(&msg_upstream_addr, buf, pastend - buf);
186 if (addr_offset < 1) {
187 char src_str[INET_ADDRSTRLEN];
188 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
189 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
15569c58 190 __func__, src_str, ifp->name);
d62a17ae 191 return -1;
192 }
193 buf += addr_offset;
194
195 /*
196 Check upstream address family
197 */
198 if (msg_upstream_addr.family != AF_INET) {
fb9670aa
DS
199 char src_str[INET_ADDRSTRLEN];
200 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
15569c58
DA
201 zlog_warn(
202 "%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
203 __func__, msg_upstream_addr.family, src_str, ifp->name);
d62a17ae 204 return -2;
205 }
206
207 remain = pastend - buf;
208 if (remain < 4) {
209 char src_str[INET_ADDRSTRLEN];
210 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
211 zlog_warn(
212 "%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
15569c58 213 __func__, remain, 4, src_str, ifp->name);
d62a17ae 214 return -4;
215 }
216
217 ++buf; /* skip reserved byte */
218 msg_num_groups = *(const uint8_t *)buf;
219 ++buf;
220 msg_holdtime = ntohs(*(const uint16_t *)buf);
221 ++buf;
222 ++buf;
223
224 if (PIM_DEBUG_PIM_J_P) {
225 char src_str[INET_ADDRSTRLEN];
226 char upstream_str[INET_ADDRSTRLEN];
227 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
228 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
229 upstream_str, sizeof(upstream_str));
230 zlog_debug(
231 "%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
15569c58
DA
232 __func__, upstream_str, msg_num_groups, msg_holdtime,
233 src_str, ifp->name);
d62a17ae 234 }
235
236 /* Scan groups */
237 for (group = 0; group < msg_num_groups; ++group) {
238 struct prefix_sg sg;
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
246 memset(&sg, 0, sizeof(struct prefix_sg));
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];
271 char upstream_str[INET_ADDRSTRLEN];
272 char group_str[INET_ADDRSTRLEN];
273 pim_inet4_dump("<src?>", src_addr, src_str,
274 sizeof(src_str));
275 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
276 upstream_str, sizeof(upstream_str));
277 pim_inet4_dump("<grp?>", sg.grp, group_str,
278 sizeof(group_str));
fb9670aa 279 zlog_debug(
d62a17ae 280 "%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s",
15569c58 281 __func__, upstream_str, group_str,
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
307 if (sg.src.s_addr == INADDR_ANY) {
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
d62a17ae 340 /* Received SG-RPT Prune delete oif from specific S,G */
341 if (starg_ch && sg_ch
342 && (msg_source_flags & PIM_RPT_BIT_MASK)
343 && !(msg_source_flags & PIM_WILDCARD_BIT_MASK)) {
344 struct pim_upstream *up = sg_ch->upstream;
345 PIM_IF_FLAG_SET_S_G_RPT(sg_ch->flags);
346 if (up) {
23fc858a 347 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 348 zlog_debug(
349 "%s: SGRpt flag is set, del inherit oif from up %s",
15569c58 350 __func__, up->sg_str);
1537a668 351 pim_channel_del_inherited_oif(
d62a17ae 352 up->channel_oil,
353 starg_ch->interface,
1b249e70 354 __func__);
d62a17ae 355 }
356 }
357 }
b0f525a8 358 if (starg_ch && !filtered)
c206937b 359 pim_ifchannel_set_star_g_join_state(starg_ch, 1, 0);
d62a17ae 360 starg_ch = NULL;
361 } /* scan groups */
362
363 return 0;
12e41d03
DL
364}
365
982bff89
DS
366/*
367 * J/P Message Format
368 *
369 * While the RFC clearly states that this is 32 bits wide, it
370 * is cheating. These fields:
371 * Encoded-Unicast format (6 bytes MIN)
372 * Encoded-Group format (8 bytes MIN)
373 * Encoded-Source format (8 bytes MIN)
374 * are *not* 32 bits wide.
375 *
376 * Nor does the RFC explicitly call out the size for:
377 * Reserved (1 byte)
378 * Num Groups (1 byte)
379 * Holdtime (2 bytes)
380 * Number of Joined Sources (2 bytes)
381 * Number of Pruned Sources (2 bytes)
382 *
383 * This leads to a missleading representation from casual
384 * reading and making assumptions. Be careful!
385 *
386 * 0 1 2 3
387 * 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
388 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
389 * |PIM Ver| Type | Reserved | Checksum |
390 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
391 * | Upstream Neighbor Address (Encoded-Unicast format) |
392 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
393 * | Reserved | Num groups | Holdtime |
394 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
395 * | Multicast Group Address 1 (Encoded-Group format) |
396 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
397 * | Number of Joined Sources | Number of Pruned Sources |
398 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
399 * | Joined Source Address 1 (Encoded-Source format) |
400 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
401 * | . |
402 * | . |
403 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
404 * | Joined Source Address n (Encoded-Source format) |
405 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
406 * | Pruned Source Address 1 (Encoded-Source format) |
407 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
408 * | . |
409 * | . |
410 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
411 * | Pruned Source Address n (Encoded-Source format) |
412 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
413 * | Multicast Group Address m (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 */
d62a17ae 432int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
12e41d03 433{
d62a17ae 434 struct pim_jp_agg_group *group;
435 struct pim_interface *pim_ifp = NULL;
436 struct pim_jp_groups *grp = NULL;
a97986ff 437 struct pim_jp *msg = NULL;
d62a17ae 438 struct listnode *node, *nnode;
439 uint8_t pim_msg[10000];
440 uint8_t *curr_ptr = pim_msg;
441 bool new_packet = true;
442 size_t packet_left = 0;
443 size_t packet_size = 0;
444 size_t group_size = 0;
445
d62a17ae 446 if (rpf->source_nexthop.interface)
447 pim_ifp = rpf->source_nexthop.interface->info;
448 else {
5e81f5dd 449 zlog_warn("%s: RPF interface is not present", __func__);
d62a17ae 450 return -1;
451 }
452
5e81f5dd
DS
453 on_trace(__func__, rpf->source_nexthop.interface,
454 rpf->rpf_addr.u.prefix4);
957d93ea 455
d62a17ae 456 if (!pim_ifp) {
5e81f5dd 457 zlog_warn("%s: multicast not enabled on interface %s", __func__,
d62a17ae 458 rpf->source_nexthop.interface->name);
459 return -1;
460 }
461
462 if (PIM_INADDR_IS_ANY(rpf->rpf_addr.u.prefix4)) {
463 if (PIM_DEBUG_PIM_J_P) {
464 char dst_str[INET_ADDRSTRLEN];
465 pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4,
466 dst_str, sizeof(dst_str));
467 zlog_debug("%s: upstream=%s is myself on interface %s",
5e81f5dd 468 __func__, dst_str,
d62a17ae 469 rpf->source_nexthop.interface->name);
470 }
471 return 0;
472 }
473
474 /*
475 RFC 4601: 4.3.1. Sending Hello Messages
476
477 Thus, if a router needs to send a Join/Prune or Assert message on
478 an interface on which it has not yet sent a Hello message with the
479 currently configured IP address, then it MUST immediately send the
480 relevant Hello message without waiting for the Hello Timer to
481 expire, followed by the Join/Prune or Assert message.
482 */
483 pim_hello_require(rpf->source_nexthop.interface);
484
485 for (ALL_LIST_ELEMENTS(groups, node, nnode, group)) {
486 if (new_packet) {
487 msg = (struct pim_jp *)pim_msg;
488
489 memset(msg, 0, sizeof(*msg));
490
491 pim_msg_addr_encode_ipv4_ucast((uint8_t *)&msg->addr,
492 rpf->rpf_addr.u.prefix4);
493 msg->reserved = 0;
494 msg->holdtime = htons(PIM_JP_HOLDTIME);
495
496 new_packet = false;
497
498 grp = &msg->groups[0];
499 curr_ptr = (uint8_t *)grp;
500 packet_size = sizeof(struct pim_msg_header);
501 packet_size += sizeof(struct pim_encoded_ipv4_unicast);
502 packet_size +=
503 4; // reserved (1) + groups (1) + holdtime (2)
504
505 packet_left = rpf->source_nexthop.interface->mtu - 24;
506 packet_left -= packet_size;
507 }
508 if (PIM_DEBUG_PIM_J_P) {
509 char dst_str[INET_ADDRSTRLEN];
510 char grp_str[INET_ADDRSTRLEN];
511 pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4,
512 dst_str, sizeof(dst_str));
513 pim_inet4_dump("<grp?>", group->group, grp_str,
514 sizeof(grp_str));
515 zlog_debug(
516 "%s: sending (G)=%s to upstream=%s on interface %s",
5e81f5dd 517 __func__, grp_str, dst_str,
d62a17ae 518 rpf->source_nexthop.interface->name);
519 }
520
521 group_size = pim_msg_get_jp_group_size(group->sources);
522 if (group_size > packet_left) {
523 pim_msg_build_header(pim_msg, packet_size,
d57a8bbf 524 PIM_MSG_TYPE_JOIN_PRUNE, false);
d62a17ae 525 if (pim_msg_send(pim_ifp->pim_sock_fd,
526 pim_ifp->primary_address,
527 qpim_all_pim_routers_addr, pim_msg,
528 packet_size,
529 rpf->source_nexthop.interface->name)) {
530 zlog_warn(
531 "%s: could not send PIM message on interface %s",
5e81f5dd 532 __func__,
d62a17ae 533 rpf->source_nexthop.interface->name);
534 }
535
536 msg = (struct pim_jp *)pim_msg;
537 memset(msg, 0, sizeof(*msg));
538
539 pim_msg_addr_encode_ipv4_ucast((uint8_t *)&msg->addr,
540 rpf->rpf_addr.u.prefix4);
541 msg->reserved = 0;
542 msg->holdtime = htons(PIM_JP_HOLDTIME);
543
544 new_packet = false;
545
546 grp = &msg->groups[0];
547 curr_ptr = (uint8_t *)grp;
548 packet_size = sizeof(struct pim_msg_header);
549 packet_size += sizeof(struct pim_encoded_ipv4_unicast);
550 packet_size +=
551 4; // reserved (1) + groups (1) + holdtime (2)
552
553 packet_left = rpf->source_nexthop.interface->mtu - 24;
554 packet_left -= packet_size;
555 }
556
557 msg->num_groups++;
558 /*
559 Build PIM message
560 */
561
562 curr_ptr += group_size;
563 packet_left -= group_size;
564 packet_size += group_size;
565 pim_msg_build_jp_groups(grp, group, group_size);
566
567 pim_ifp->pim_ifstat_join_send += ntohs(grp->joins);
568 pim_ifp->pim_ifstat_prune_send += ntohs(grp->prunes);
569
570 if (PIM_DEBUG_PIM_TRACE)
571 zlog_debug(
572 "%s: interface %s num_joins %u num_prunes %u",
5e81f5dd 573 __func__, rpf->source_nexthop.interface->name,
d62a17ae 574 ntohs(grp->joins), ntohs(grp->prunes));
575
576 grp = (struct pim_jp_groups *)curr_ptr;
577 if (packet_left < sizeof(struct pim_jp_groups)
578 || msg->num_groups == 255) {
579 pim_msg_build_header(pim_msg, packet_size,
d57a8bbf 580 PIM_MSG_TYPE_JOIN_PRUNE, false);
d62a17ae 581 if (pim_msg_send(pim_ifp->pim_sock_fd,
582 pim_ifp->primary_address,
583 qpim_all_pim_routers_addr, pim_msg,
584 packet_size,
585 rpf->source_nexthop.interface->name)) {
586 zlog_warn(
587 "%s: could not send PIM message on interface %s",
5e81f5dd 588 __func__,
d62a17ae 589 rpf->source_nexthop.interface->name);
590 }
591
592 new_packet = true;
593 }
594 }
595
596
597 if (!new_packet) {
598 // msg->num_groups = htons (msg->num_groups);
599 pim_msg_build_header(pim_msg, packet_size,
d57a8bbf 600 PIM_MSG_TYPE_JOIN_PRUNE, false);
d62a17ae 601 if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
602 qpim_all_pim_routers_addr, pim_msg,
603 packet_size,
604 rpf->source_nexthop.interface->name)) {
605 zlog_warn(
606 "%s: could not send PIM message on interface %s",
5e81f5dd 607 __func__, rpf->source_nexthop.interface->name);
d62a17ae 608 }
609 }
610 return 0;
12e41d03 611}