1 /*
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  */
19 
20 #include <zebra.h>
21 
22 #include "log.h"
23 #include "prefix.h"
24 #include "if.h"
25 #include "vty.h"
26 #include "plist.h"
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"
34 #include "pim_oil.h"
35 #include "pim_iface.h"
36 #include "pim_hello.h"
37 #include "pim_ifchannel.h"
38 #include "pim_rpf.h"
39 #include "pim_rp.h"
40 #include "pim_jp_agg.h"
41 #include "pim_util.h"
42 
on_trace(const char * label,struct interface * ifp,struct in_addr src)43 static void on_trace(const char *label, struct interface *ifp,
44 		     struct in_addr src)
45 {
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 	}
51 }
52 
recv_join(struct interface * ifp,struct pim_neighbor * neigh,uint16_t holdtime,struct in_addr upstream,struct prefix_sg * sg,uint8_t source_flags)53 static 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)
56 {
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));
65 		zlog_debug(
66 			"%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
67 			__func__, pim_str_sg_dump(sg),
68 			!!(source_flags & PIM_RPT_BIT_MASK),
69 			!!(source_flags & PIM_WILDCARD_BIT_MASK), up_str,
70 			holdtime, neigh_str, ifp->name);
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)) {
84 		struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp);
85 
86 		if (!rp) {
87 			zlog_warn("%s: Lookup of RP failed for %pSG4", __func__,
88 				  sg);
89 			return;
90 		}
91 		/*
92 		 * If the RP sent in the message is not
93 		 * our RP for the group, drop the message
94 		 */
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));
102 			zlog_warn(
103 				"%s: Specified RP(%s) in join is different than our configured RP(%s)",
104 				__func__, received_rp, local_rp);
105 			return;
106 		}
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);
114 }
115 
recv_prune(struct interface * ifp,struct pim_neighbor * neigh,uint16_t holdtime,struct in_addr upstream,struct prefix_sg * sg,uint8_t source_flags)116 static 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)
119 {
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));
128 		zlog_debug(
129 			"%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
130 			__func__, pim_str_sg_dump(sg),
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)) {
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];
150 
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);
155 		}
156 
157 		sg->src.s_addr = INADDR_ANY;
158 	}
159 
160 	pim_ifchannel_prune(ifp, upstream, sg, source_flags, holdtime);
161 }
162 
pim_joinprune_recv(struct interface * ifp,struct pim_neighbor * neigh,struct in_addr src_addr,uint8_t * tlv_buf,int tlv_buf_size)163 int 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)
166 {
167 	struct prefix msg_upstream_addr;
168 	struct pim_interface *pim_ifp;
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;
179 	pim_ifp = ifp->info;
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",
190 			  __func__, src_str, ifp->name);
191 		return -1;
192 	}
193 	buf += addr_offset;
194 
195 	/*
196 	  Check upstream address family
197 	 */
198 	if (msg_upstream_addr.family != AF_INET) {
199 		char src_str[INET_ADDRSTRLEN];
200 		pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
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);
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",
213 			__func__, remain, 4, src_str, ifp->name);
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",
232 			__func__, upstream_str, msg_num_groups, msg_holdtime,
233 			src_str, ifp->name);
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;
244 		bool filtered = false;
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",
260 				__func__, remain, 4, src_str, ifp->name);
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));
279 			zlog_debug(
280 				"%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s",
281 				__func__, upstream_str, group_str,
282 				msg_num_joined_sources, msg_num_pruned_sources,
283 				src_str, ifp->name);
284 		}
285 
286 		/* boundary check */
287 		filtered = pim_is_group_filtered(pim_ifp, &sg.grp);
288 
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 
299 			/* if we are filtering this group, skip the join */
300 			if (filtered)
301 				continue;
302 
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) {
308 				starg_ch = pim_ifchannel_find(ifp, &sg);
309 				if (starg_ch)
310 					pim_ifchannel_set_star_g_join_state(
311 						starg_ch, 0, 1);
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 
323 			buf += addr_offset;
324 
325 			/* if we are filtering this group, skip the prune */
326 			if (filtered)
327 				continue;
328 
329 			recv_prune(ifp, neigh, msg_holdtime,
330 				   msg_upstream_addr.u.prefix4, &sg,
331 				   msg_source_flags);
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 
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) {
347 					if (PIM_DEBUG_PIM_TRACE)
348 						zlog_debug(
349 							"%s: SGRpt flag is set, del inherit oif from up %s",
350 							__func__, up->sg_str);
351 					pim_channel_del_inherited_oif(
352 						up->channel_oil,
353 						starg_ch->interface,
354 						__func__);
355 				}
356 			}
357 		}
358 		if (starg_ch && !filtered)
359 			pim_ifchannel_set_star_g_join_state(starg_ch, 1, 0);
360 		starg_ch = NULL;
361 	} /* scan groups */
362 
363 	return 0;
364 }
365 
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  */
pim_joinprune_send(struct pim_rpf * rpf,struct list * groups)432 int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
433 {
434 	struct pim_jp_agg_group *group;
435 	struct pim_interface *pim_ifp = NULL;
436 	struct pim_jp_groups *grp = NULL;
437 	struct pim_jp *msg = NULL;
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 
446 	if (rpf->source_nexthop.interface)
447 		pim_ifp = rpf->source_nexthop.interface->info;
448 	else {
449 		zlog_warn("%s: RPF interface is not present", __func__);
450 		return -1;
451 	}
452 
453 	on_trace(__func__, rpf->source_nexthop.interface,
454 		 rpf->rpf_addr.u.prefix4);
455 
456 	if (!pim_ifp) {
457 		zlog_warn("%s: multicast not enabled on interface %s", __func__,
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",
468 				   __func__, dst_str,
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",
517 				__func__, grp_str, dst_str,
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,
524 					     PIM_MSG_TYPE_JOIN_PRUNE, false);
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",
532 					__func__,
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",
573 				__func__, rpf->source_nexthop.interface->name,
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,
580 					     PIM_MSG_TYPE_JOIN_PRUNE, false);
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",
588 					__func__,
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,
600 				     PIM_MSG_TYPE_JOIN_PRUNE, false);
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",
607 				__func__, rpf->source_nexthop.interface->name);
608 		}
609 	}
610 	return 0;
611 }
612