]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_join.c
*: add indent control files
[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"
12e41d03 41
4950938e
DS
42static void
43on_trace (const char *label,
44 struct interface *ifp, struct in_addr src)
12e41d03
DL
45{
46 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb 47 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
48 pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
49 zlog_debug("%s: from %s on %s",
50 label, src_str, ifp->name);
51 }
52}
53
54static void recv_join(struct interface *ifp,
55 struct pim_neighbor *neigh,
56 uint16_t holdtime,
57 struct in_addr upstream,
cf4ea1c4 58 struct prefix_sg *sg,
12e41d03
DL
59 uint8_t source_flags)
60{
39438188
CS
61 struct pim_interface *pim_ifp = NULL;
62
12e41d03 63 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb
DW
64 char up_str[INET_ADDRSTRLEN];
65 char neigh_str[INET_ADDRSTRLEN];
12e41d03 66 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
12e41d03 67 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
ee1a477a 68 zlog_warn("%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
12e41d03 69 __PRETTY_FUNCTION__,
cf4ea1c4 70 pim_str_sg_dump (sg),
12e41d03
DL
71 source_flags & PIM_RPT_BIT_MASK,
72 source_flags & PIM_WILDCARD_BIT_MASK,
73 up_str, holdtime, neigh_str, ifp->name);
74 }
346cffe3 75
39438188
CS
76 pim_ifp = ifp->info;
77 zassert(pim_ifp);
78
79 ++pim_ifp->pim_ifstat_join_recv;
80
346cffe3
DS
81 /*
82 * If the RPT and WC are set it's a (*,G)
83 * and the source is the RP
84 */
85 if ((source_flags & PIM_RPT_BIT_MASK) &&
86 (source_flags & PIM_WILDCARD_BIT_MASK))
87 {
cf4ea1c4 88 struct pim_rpf *rp = RP (sg->grp);
346cffe3
DS
89
90 /*
91 * If the RP sent in the message is not
92 * our RP for the group, drop the message
93 */
cf4ea1c4 94 if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
346cffe3
DS
95 return;
96
cf4ea1c4 97 sg->src.s_addr = INADDR_ANY;
346cffe3
DS
98 }
99
12e41d03
DL
100 /* Restart join expiry timer */
101 pim_ifchannel_join_add(ifp, neigh->source_addr, upstream,
cf4ea1c4 102 sg, source_flags, holdtime);
6c629103 103
12e41d03
DL
104}
105
106static void recv_prune(struct interface *ifp,
107 struct pim_neighbor *neigh,
108 uint16_t holdtime,
109 struct in_addr upstream,
cf4ea1c4 110 struct prefix_sg *sg,
12e41d03
DL
111 uint8_t source_flags)
112{
39438188
CS
113 struct pim_interface *pim_ifp = NULL;
114
12e41d03 115 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb
DW
116 char up_str[INET_ADDRSTRLEN];
117 char neigh_str[INET_ADDRSTRLEN];
12e41d03 118 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
12e41d03 119 pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
7bd2c6fa 120 zlog_warn("%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
12e41d03 121 __PRETTY_FUNCTION__,
cf4ea1c4 122 pim_str_sg_dump (sg),
12e41d03
DL
123 source_flags & PIM_RPT_BIT_MASK,
124 source_flags & PIM_WILDCARD_BIT_MASK,
125 up_str, holdtime, neigh_str, ifp->name);
126 }
035f28f6 127
39438188
CS
128 pim_ifp = ifp->info;
129 zassert(pim_ifp);
130
131 ++pim_ifp->pim_ifstat_prune_recv;
132
035f28f6
DS
133 if ((source_flags & PIM_RPT_BIT_MASK) &&
134 (source_flags & PIM_WILDCARD_BIT_MASK))
135 {
cf4ea1c4 136 struct pim_rpf *rp = RP (sg->grp);
035f28f6
DS
137
138 // Ignoring Prune *,G's at the moment.
cf4ea1c4 139 if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
035f28f6
DS
140 return;
141
cf4ea1c4 142 sg->src.s_addr = INADDR_ANY;
035f28f6 143 }
dc686f82 144
cf4ea1c4 145 pim_ifchannel_prune(ifp, upstream, sg, source_flags, holdtime);
6c629103 146
12e41d03
DL
147}
148
149int pim_joinprune_recv(struct interface *ifp,
150 struct pim_neighbor *neigh,
151 struct in_addr src_addr,
152 uint8_t *tlv_buf, int tlv_buf_size)
153{
154 struct prefix msg_upstream_addr;
155 uint8_t msg_num_groups;
156 uint16_t msg_holdtime;
157 int addr_offset;
158 uint8_t *buf;
159 uint8_t *pastend;
160 int remain;
161 int group;
162
12e41d03
DL
163 buf = tlv_buf;
164 pastend = tlv_buf + tlv_buf_size;
165
166 /*
167 Parse ucast addr
168 */
4416b1f6
DS
169 addr_offset = pim_parse_addr_ucast (&msg_upstream_addr,
170 buf, pastend - buf);
12e41d03 171 if (addr_offset < 1) {
eaa54bdb 172 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
173 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
174 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
175 __PRETTY_FUNCTION__,
176 src_str, ifp->name);
177 return -1;
178 }
179 buf += addr_offset;
180
181 /*
182 Check upstream address family
183 */
184 if (msg_upstream_addr.family != AF_INET) {
4950938e 185 if (PIM_DEBUG_PIM_J_P) {
eaa54bdb 186 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
187 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
188 zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
189 __PRETTY_FUNCTION__,
190 msg_upstream_addr.family, src_str, ifp->name);
191 }
192 return -2;
193 }
194
195 remain = pastend - buf;
196 if (remain < 4) {
eaa54bdb 197 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
198 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
199 zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
200 __PRETTY_FUNCTION__,
201 remain, 4, src_str, ifp->name);
202 return -4;
203 }
204
205 ++buf; /* skip reserved byte */
206 msg_num_groups = *(const uint8_t *) buf;
207 ++buf;
208 msg_holdtime = ntohs(*(const uint16_t *) buf);
209 ++buf;
210 ++buf;
211
4950938e 212 if (PIM_DEBUG_PIM_J_P) {
eaa54bdb
DW
213 char src_str[INET_ADDRSTRLEN];
214 char upstream_str[INET_ADDRSTRLEN];
12e41d03
DL
215 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
216 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
217 upstream_str, sizeof(upstream_str));
4950938e
DS
218 zlog_debug ("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
219 __PRETTY_FUNCTION__,
220 upstream_str, msg_num_groups, msg_holdtime,
221 src_str, ifp->name);
12e41d03
DL
222 }
223
224 /* Scan groups */
225 for (group = 0; group < msg_num_groups; ++group) {
bce0e645 226 struct prefix_sg sg;
12e41d03
DL
227 uint8_t msg_source_flags;
228 uint16_t msg_num_joined_sources;
229 uint16_t msg_num_pruned_sources;
230 int source;
ee22bbae
CS
231 struct pim_ifchannel *starg_ch = NULL, *sg_ch = NULL;
232 uint8_t starg_alone = 0;
12e41d03 233
53e39e14 234 memset (&sg, 0, sizeof (struct prefix_sg));
bce0e645 235 addr_offset = pim_parse_addr_group (&sg,
4416b1f6 236 buf, pastend - buf);
12e41d03
DL
237 if (addr_offset < 1) {
238 return -5;
239 }
240 buf += addr_offset;
241
242 remain = pastend - buf;
243 if (remain < 4) {
eaa54bdb 244 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
245 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
246 zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
247 __PRETTY_FUNCTION__,
248 remain, 4, src_str, ifp->name);
249 return -6;
250 }
251
252 msg_num_joined_sources = ntohs(*(const uint16_t *) buf);
253 buf += 2;
254 msg_num_pruned_sources = ntohs(*(const uint16_t *) buf);
255 buf += 2;
256
4950938e 257 if (PIM_DEBUG_PIM_J_P) {
eaa54bdb
DW
258 char src_str[INET_ADDRSTRLEN];
259 char upstream_str[INET_ADDRSTRLEN];
260 char group_str[INET_ADDRSTRLEN];
12e41d03
DL
261 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
262 pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
263 upstream_str, sizeof(upstream_str));
bce0e645 264 pim_inet4_dump("<grp?>", sg.grp,
12e41d03 265 group_str, sizeof(group_str));
bce0e645 266 zlog_warn("%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s",
12e41d03 267 __PRETTY_FUNCTION__,
bce0e645 268 upstream_str, group_str,
12e41d03
DL
269 msg_num_joined_sources, msg_num_pruned_sources,
270 src_str, ifp->name);
271 }
272
273 /* Scan joined sources */
274 for (source = 0; source < msg_num_joined_sources; ++source) {
a7762e07 275 addr_offset = pim_parse_addr_source (&sg,
4416b1f6
DS
276 &msg_source_flags,
277 buf, pastend - buf);
12e41d03
DL
278 if (addr_offset < 1) {
279 return -7;
280 }
281
282 buf += addr_offset;
283
284 recv_join(ifp, neigh, msg_holdtime,
285 msg_upstream_addr.u.prefix4,
cf4ea1c4 286 &sg,
12e41d03 287 msg_source_flags);
220d8a49
DS
288
289 if (sg.src.s_addr == INADDR_ANY)
290 {
ee22bbae
CS
291 starg_alone = 1;
292 starg_ch = pim_ifchannel_find (ifp, &sg);
293 if (starg_ch)
294 pim_ifchannel_set_star_g_join_state (starg_ch, 0, msg_source_flags, 1, starg_alone);
220d8a49 295 }
12e41d03
DL
296 }
297
298 /* Scan pruned sources */
299 for (source = 0; source < msg_num_pruned_sources; ++source) {
a7762e07 300 addr_offset = pim_parse_addr_source (&sg,
4416b1f6
DS
301 &msg_source_flags,
302 buf, pastend - buf);
12e41d03
DL
303 if (addr_offset < 1) {
304 return -8;
305 }
306
ee22bbae 307 sg_ch = pim_ifchannel_find (ifp, &sg);
12e41d03 308
ee22bbae
CS
309 buf += addr_offset;
310 starg_alone = 0;
12e41d03
DL
311 recv_prune(ifp, neigh, msg_holdtime,
312 msg_upstream_addr.u.prefix4,
cf4ea1c4 313 &sg,
12e41d03 314 msg_source_flags);
ee22bbae
CS
315
316 /* Received SG-RPT Prune delete oif from specific S,G */
317 if (starg_ch && sg_ch && (msg_source_flags & PIM_RPT_BIT_MASK)
318 && !(msg_source_flags & PIM_WILDCARD_BIT_MASK))
319 {
320 struct pim_upstream *up = sg_ch->upstream;
321 PIM_IF_FLAG_SET_S_G_RPT(sg_ch->flags);
322 if (up)
323 {
324 if (PIM_DEBUG_TRACE)
325 zlog_debug ("%s: SGRpt flag is set, del inherit oif from up %s",
326 __PRETTY_FUNCTION__, up->sg_str);
327 pim_channel_del_oif (up->channel_oil, starg_ch->interface, PIM_OIF_FLAG_PROTO_STAR);
328 }
329 }
12e41d03 330 }
ee22bbae
CS
331 if (starg_ch)
332 pim_ifchannel_set_star_g_join_state (starg_ch, 1, msg_source_flags, 0, starg_alone);
333 starg_ch = NULL;
12e41d03
DL
334 } /* scan groups */
335
336 return 0;
337}
338
982bff89
DS
339/*
340 * J/P Message Format
341 *
342 * While the RFC clearly states that this is 32 bits wide, it
343 * is cheating. These fields:
344 * Encoded-Unicast format (6 bytes MIN)
345 * Encoded-Group format (8 bytes MIN)
346 * Encoded-Source format (8 bytes MIN)
347 * are *not* 32 bits wide.
348 *
349 * Nor does the RFC explicitly call out the size for:
350 * Reserved (1 byte)
351 * Num Groups (1 byte)
352 * Holdtime (2 bytes)
353 * Number of Joined Sources (2 bytes)
354 * Number of Pruned Sources (2 bytes)
355 *
356 * This leads to a missleading representation from casual
357 * reading and making assumptions. Be careful!
358 *
359 * 0 1 2 3
360 * 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
361 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
362 * |PIM Ver| Type | Reserved | Checksum |
363 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
364 * | Upstream Neighbor Address (Encoded-Unicast format) |
365 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
366 * | Reserved | Num groups | Holdtime |
367 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
368 * | Multicast Group Address 1 (Encoded-Group format) |
369 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
370 * | Number of Joined Sources | Number of Pruned Sources |
371 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
372 * | Joined Source Address 1 (Encoded-Source format) |
373 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
374 * | . |
375 * | . |
376 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
377 * | Joined Source Address n (Encoded-Source format) |
378 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
379 * | Pruned Source Address 1 (Encoded-Source format) |
380 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
381 * | . |
382 * | . |
383 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
384 * | Pruned Source Address n (Encoded-Source format) |
385 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
386 * | Multicast Group Address m (Encoded-Group format) |
387 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
388 * | Number of Joined Sources | Number of Pruned Sources |
389 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
390 * | Joined Source Address 1 (Encoded-Source format) |
391 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
392 * | . |
393 * | . |
394 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
395 * | Joined Source Address n (Encoded-Source format) |
396 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
397 * | Pruned Source Address 1 (Encoded-Source format) |
398 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
399 * | . |
400 * | . |
401 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
402 * | Pruned Source Address n (Encoded-Source format) |
403 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
404 */
b5e2377c 405int pim_joinprune_send(struct pim_rpf *rpf,
982bff89 406 struct list *groups)
12e41d03 407{
982bff89 408 struct pim_jp_agg_group *group;
4ba87bb9 409 struct pim_interface *pim_ifp = NULL;
982bff89
DS
410 struct pim_jp_groups *grp = NULL;
411 struct pim_jp *msg;
412 struct listnode *node, *nnode;
413 uint8_t pim_msg[10000];
414 uint8_t *curr_ptr = pim_msg;
415 bool new_packet = true;
416 size_t packet_left = 0;
417 size_t packet_size = 0;
418 size_t group_size = 0;
12e41d03 419
b5e2377c 420 on_trace (__PRETTY_FUNCTION__, rpf->source_nexthop.interface, rpf->rpf_addr.u.prefix4);
4950938e 421
1131c2eb
CS
422 if (rpf->source_nexthop.interface)
423 pim_ifp = rpf->source_nexthop.interface->info;
424 else
425 {
426 zlog_warn ("%s: RPF interface is not present", __PRETTY_FUNCTION__);
427 return -1;
428 }
12e41d03 429
4ba87bb9
CS
430 if (!pim_ifp)
431 {
432 zlog_warn ("%s: multicast not enabled on interface %s",
b5e2377c
DS
433 __PRETTY_FUNCTION__,
434 rpf->source_nexthop.interface->name);
4ba87bb9
CS
435 return -1;
436 }
12e41d03 437
982bff89
DS
438 if (PIM_INADDR_IS_ANY(rpf->rpf_addr.u.prefix4))
439 {
440 if (PIM_DEBUG_PIM_J_P) {
441 char dst_str[INET_ADDRSTRLEN];
442 pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str));
443 zlog_debug("%s: upstream=%s is myself on interface %s",
444 __PRETTY_FUNCTION__,
445 dst_str, rpf->source_nexthop.interface->name);
446 }
447 return 0;
12e41d03 448 }
12e41d03
DL
449
450 /*
451 RFC 4601: 4.3.1. Sending Hello Messages
452
453 Thus, if a router needs to send a Join/Prune or Assert message on
454 an interface on which it has not yet sent a Hello message with the
455 currently configured IP address, then it MUST immediately send the
456 relevant Hello message without waiting for the Hello Timer to
457 expire, followed by the Join/Prune or Assert message.
458 */
b5e2377c 459 pim_hello_require(rpf->source_nexthop.interface);
12e41d03 460
982bff89
DS
461 for (ALL_LIST_ELEMENTS(groups, node, nnode, group))
462 {
463 if (new_packet)
464 {
465 msg = (struct pim_jp *)pim_msg;
12e41d03 466
982bff89 467 memset(msg, 0, sizeof (*msg));
12e41d03 468
982bff89
DS
469 pim_msg_addr_encode_ipv4_ucast ((uint8_t *)&msg->addr, rpf->rpf_addr.u.prefix4);
470 msg->reserved = 0;
471 msg->holdtime = htons(PIM_JP_HOLDTIME);
48f6dc2d 472
982bff89
DS
473 new_packet = false;
474
475 grp = &msg->groups[0];
476 curr_ptr = (uint8_t *)grp;
477 packet_size = sizeof (struct pim_msg_header);
478 packet_size += sizeof (struct pim_encoded_ipv4_unicast);
479 packet_size += 4; // reserved (1) + groups (1) + holdtime (2)
480
481 packet_left = rpf->source_nexthop.interface->mtu - 24;
482 packet_left -= packet_size;
483 }
484 if (PIM_DEBUG_PIM_J_P) {
485 char dst_str[INET_ADDRSTRLEN];
486 char grp_str[INET_ADDRSTRLEN];
487 pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str));
488 pim_inet4_dump("<grp?>", group->group, grp_str, sizeof(grp_str));
489 zlog_debug("%s: sending (G)=%s to upstream=%s on interface %s",
490 __PRETTY_FUNCTION__,
491 grp_str, dst_str, rpf->source_nexthop.interface->name);
492 }
493
494 group_size = pim_msg_get_jp_group_size (group->sources);
495 if (group_size > packet_left)
496 {
497 pim_msg_build_header (pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE);
498 if (pim_msg_send(pim_ifp->pim_sock_fd,
499 pim_ifp->primary_address,
500 qpim_all_pim_routers_addr,
501 pim_msg,
502 packet_size,
503 rpf->source_nexthop.interface->name)) {
504 zlog_warn("%s: could not send PIM message on interface %s",
505 __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name);
506 }
507
508 msg = (struct pim_jp *)pim_msg;
509 memset(msg, 0, sizeof (*msg));
510
511 pim_msg_addr_encode_ipv4_ucast ((uint8_t *)&msg->addr, rpf->rpf_addr.u.prefix4);
512 msg->reserved = 0;
513 msg->holdtime = htons(PIM_JP_HOLDTIME);
514
515 new_packet = false;
516
517 grp = &msg->groups[0];
518 curr_ptr = (uint8_t *)grp;
519 packet_size = sizeof (struct pim_msg_header);
520 packet_size += sizeof (struct pim_encoded_ipv4_unicast);
521 packet_size += 4; // reserved (1) + groups (1) + holdtime (2)
522
523 packet_left = rpf->source_nexthop.interface->mtu - 24;
524 packet_left -= packet_size;
525 }
12e41d03 526
982bff89
DS
527 msg->num_groups++;
528 /*
529 Build PIM message
530 */
531
532 curr_ptr += group_size;
533 packet_left -= group_size;
534 packet_size += group_size;
e7eefda4 535 pim_msg_build_jp_groups (grp, group, group_size);
982bff89 536
39438188
CS
537 pim_ifp->pim_ifstat_join_send += ntohs(grp->joins);
538 pim_ifp->pim_ifstat_prune_send += ntohs(grp->prunes);
539
ee22bbae
CS
540 if (PIM_DEBUG_PIM_TRACE)
541 zlog_debug ("%s: interface %s num_joins %u num_prunes %u", __PRETTY_FUNCTION__,
542 rpf->source_nexthop.interface->name, ntohs(grp->joins), ntohs (grp->prunes));
543
982bff89
DS
544 grp = (struct pim_jp_groups *)curr_ptr;
545 if (packet_left < sizeof (struct pim_jp_groups) || msg->num_groups == 255)
546 {
547 pim_msg_build_header (pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE);
548 if (pim_msg_send(pim_ifp->pim_sock_fd,
549 pim_ifp->primary_address,
550 qpim_all_pim_routers_addr,
551 pim_msg,
552 packet_size,
553 rpf->source_nexthop.interface->name)) {
554 zlog_warn("%s: could not send PIM message on interface %s",
555 __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name);
556 }
557
558 new_packet = true;
559 }
560 }
561
562
563 if (!new_packet)
564 {
565 //msg->num_groups = htons (msg->num_groups);
566 pim_msg_build_header (pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE);
567 if (pim_msg_send(pim_ifp->pim_sock_fd,
568 pim_ifp->primary_address,
569 qpim_all_pim_routers_addr,
570 pim_msg,
571 packet_size,
572 rpf->source_nexthop.interface->name)) {
573 zlog_warn("%s: could not send PIM message on interface %s",
574 __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name);
575 }
576 }
12e41d03
DL
577 return 0;
578}